You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1359 lines
47 KiB

  1. /*
  2. * melib - gpgme module
  3. *
  4. * Copyright 2020 Manos Pitsidianakis
  5. *
  6. * This file is part of meli.
  7. *
  8. * meli is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation, either version 3 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * meli is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with meli. If not, see <http://www.gnu.org/licenses/>.
  20. */
  21. use crate::email::{
  22. pgp::{DecryptionMetadata, Recipient},
  23. Address,
  24. };
  25. use crate::error::{ErrorKind, IntoMeliError, MeliError, Result, ResultIntoMeliError};
  26. use futures::FutureExt;
  27. use serde::{
  28. de::{self, Deserialize},
  29. Deserializer, Serialize, Serializer,
  30. };
  31. use smol::Async;
  32. use std::borrow::Cow;
  33. use std::collections::HashMap;
  34. use std::ffi::{CStr, CString, OsStr};
  35. use std::future::Future;
  36. use std::io::Seek;
  37. use std::os::unix::ffi::OsStrExt;
  38. use std::os::unix::io::{AsRawFd, RawFd};
  39. use std::path::Path;
  40. use std::sync::{Arc, Mutex};
  41. const GPGME_MIN_VERSION: &str = "1.12.0";
  42. macro_rules! call {
  43. ($lib:expr, $func:ty) => {{
  44. let func: libloading::Symbol<$func> =
  45. $lib.get(stringify!($func).as_bytes()).expect(concat!(
  46. "Could not use libgpgme: symbol ",
  47. stringify!($func),
  48. " not found!"
  49. ));
  50. func
  51. }};
  52. }
  53. macro_rules! c_string_literal {
  54. ($lit:literal) => {{
  55. unsafe {
  56. CStr::from_bytes_with_nul_unchecked(concat!($lit, "\0").as_bytes()).as_ptr()
  57. as *const ::std::os::raw::c_char
  58. }
  59. }};
  60. }
  61. mod bindings;
  62. use bindings::*;
  63. mod io;
  64. #[derive(Debug, Clone, Copy, PartialEq)]
  65. pub enum GpgmeFlag {
  66. ///"auto-key-retrieve"
  67. AutoKeyRetrieve,
  68. OfflineMode,
  69. AsciiArmor,
  70. }
  71. bitflags! {
  72. pub struct LocateKey: u8 {
  73. /// Locate a key using DNS CERT, as specified in RFC-4398.
  74. const CERT = 0b1;
  75. /// Locate a key using DNS PKA.
  76. const PKA = 0b10;
  77. /// Locate a key using DANE, as specified in draft-ietf-dane-openpgpkey-05.txt.
  78. const DANE = 0b100;
  79. /// Locate a key using the Web Key Directory protocol.
  80. const WKD = 0b1000;
  81. /// Using DNS Service Discovery, check the domain in question for any LDAP keyservers to use. If this fails, attempt to locate the key using the PGP Universal method of checking β€˜ldap://keys.(thedomain)’.
  82. const LDAP = 0b10000;
  83. /// Locate a key using a keyserver.
  84. const KEYSERVER = 0b100000;
  85. /// In addition, a keyserver URL as used in the dirmngr configuration may be used here to query that particular keyserver.
  86. const KEYSERVER_URL = 0b1000000;
  87. /// Locate the key using the local keyrings. This mechanism allows the user to select the order a local key lookup is done. Thus using β€˜--auto-key-locate local’ is identical to --no-auto-key-locate.
  88. const LOCAL = 0b10000000;
  89. /// This flag disables the standard local key lookup, done before any of the mechanisms defined by the --auto-key-locate are tried. The position of this mechanism in the list does not matter. It is not required if local is also used.
  90. const NODEFAULT = 0;
  91. }
  92. }
  93. impl<'de> Deserialize<'de> for LocateKey {
  94. fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
  95. where
  96. D: Deserializer<'de>,
  97. {
  98. if let Ok(s) = <String>::deserialize(deserializer) {
  99. LocateKey::from_string_de::<'de, D, String>(s)
  100. } else {
  101. Err(de::Error::custom("LocateKey value must be a string."))
  102. }
  103. }
  104. }
  105. impl Serialize for LocateKey {
  106. fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
  107. where
  108. S: Serializer,
  109. {
  110. serializer.serialize_str(&self.to_string())
  111. }
  112. }
  113. impl LocateKey {
  114. pub fn from_string_de<'de, D, T: AsRef<str>>(s: T) -> std::result::Result<Self, D::Error>
  115. where
  116. D: Deserializer<'de>,
  117. {
  118. Ok(match s.as_ref().trim() {
  119. s if s.eq_ignore_ascii_case("cert") => LocateKey::CERT,
  120. s if s.eq_ignore_ascii_case("pka") => LocateKey::PKA,
  121. s if s.eq_ignore_ascii_case("dane") => LocateKey::DANE,
  122. s if s.eq_ignore_ascii_case("wkd") => LocateKey::WKD,
  123. s if s.eq_ignore_ascii_case("ldap") => LocateKey::LDAP,
  124. s if s.eq_ignore_ascii_case("keyserver") => LocateKey::KEYSERVER,
  125. s if s.eq_ignore_ascii_case("keyserver-url") => LocateKey::KEYSERVER_URL,
  126. s if s.eq_ignore_ascii_case("local") => LocateKey::LOCAL,
  127. combination if combination.contains(",") => {
  128. let mut ret = LocateKey::NODEFAULT;
  129. for c in combination.trim().split(",") {
  130. ret |= Self::from_string_de::<'de, D, &str>(c.trim())?;
  131. }
  132. ret
  133. }
  134. _ => {
  135. return Err(de::Error::custom(
  136. r#"Takes valid auto-key-locate GPG values: "cert", "pka", "dane", "wkd", "ldap", "keyserver", "keyserver-URL", "local", "nodefault""#,
  137. ))
  138. }
  139. })
  140. }
  141. }
  142. impl std::fmt::Display for LocateKey {
  143. fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
  144. if *self == LocateKey::NODEFAULT {
  145. write!(fmt, "clear,nodefault")
  146. } else {
  147. let mut accum = String::new();
  148. macro_rules! is_set {
  149. ($flag:expr, $string:literal) => {{
  150. if self.intersects($flag) {
  151. accum.push_str($string);
  152. accum.push_str(",");
  153. }
  154. }};
  155. }
  156. is_set!(LocateKey::CERT, "cert");
  157. is_set!(LocateKey::PKA, "pka");
  158. is_set!(LocateKey::WKD, "wkd");
  159. is_set!(LocateKey::LDAP, "ldap");
  160. is_set!(LocateKey::KEYSERVER, "keyserver");
  161. is_set!(LocateKey::KEYSERVER_URL, "keyserver-url");
  162. is_set!(LocateKey::LOCAL, "local");
  163. accum.pop();
  164. write!(fmt, "{}", accum)
  165. }
  166. }
  167. }
  168. struct IoState {
  169. max_idx: usize,
  170. ops: HashMap<usize, GpgmeFd>,
  171. done: Arc<Mutex<Option<Result<()>>>>,
  172. sender: smol::channel::Sender<()>,
  173. receiver: smol::channel::Receiver<()>,
  174. key_sender: smol::channel::Sender<KeyInner>,
  175. key_receiver: smol::channel::Receiver<KeyInner>,
  176. lib: Arc<libloading::Library>,
  177. }
  178. unsafe impl Send for IoState {}
  179. unsafe impl Sync for IoState {}
  180. pub struct ContextInner {
  181. inner: core::ptr::NonNull<gpgme_context>,
  182. lib: Arc<libloading::Library>,
  183. }
  184. unsafe impl Send for ContextInner {}
  185. unsafe impl Sync for ContextInner {}
  186. pub struct Context {
  187. inner: Arc<ContextInner>,
  188. io_state: Arc<Mutex<IoState>>,
  189. }
  190. unsafe impl Send for Context {}
  191. unsafe impl Sync for Context {}
  192. impl Drop for ContextInner {
  193. #[inline]
  194. fn drop(&mut self) {
  195. unsafe { call!(self.lib, gpgme_release)(self.inner.as_mut()) }
  196. }
  197. }
  198. impl Context {
  199. pub fn new() -> Result<Self> {
  200. let version = CString::new(GPGME_MIN_VERSION).unwrap();
  201. let lib = Arc::new(libloading::Library::new(libloading::library_filename(
  202. "gpgme",
  203. ))?);
  204. if unsafe { call!(&lib, gpgme_check_version)(version.as_c_str().as_ptr() as *mut _) }
  205. .is_null()
  206. {
  207. return Err(MeliError::new(format!(
  208. "Could not use libgpgme: requested version compatible with {} but got {}",
  209. GPGME_MIN_VERSION,
  210. unsafe {
  211. CStr::from_ptr(call!(&lib, gpgme_check_version)(std::ptr::null_mut()))
  212. .to_string_lossy()
  213. },
  214. ))
  215. .set_kind(ErrorKind::External));
  216. };
  217. let (sender, receiver) = smol::channel::unbounded();
  218. let (key_sender, key_receiver) = smol::channel::unbounded();
  219. let mut ptr = core::ptr::null_mut();
  220. let io_state = Arc::new(Mutex::new(IoState {
  221. max_idx: 0,
  222. ops: HashMap::default(),
  223. done: Arc::new(Mutex::new(None)),
  224. sender,
  225. receiver,
  226. key_sender,
  227. key_receiver,
  228. lib: lib.clone(),
  229. }));
  230. let add_priv_data = io_state.clone();
  231. let event_priv_data = io_state.clone();
  232. let mut io_cbs = gpgme_io_cbs {
  233. add: Some(io::gpgme_register_io_cb),
  234. add_priv: Arc::into_raw(add_priv_data) as *mut ::std::os::raw::c_void, //add_priv: *mut ::std::os::raw::c_void,
  235. remove: Some(io::gpgme_remove_io_cb),
  236. event: Some(io::gpgme_event_io_cb),
  237. event_priv: Arc::into_raw(event_priv_data) as *mut ::std::os::raw::c_void, //pub event_priv: *mut ::std::os::raw::c_void,
  238. };
  239. unsafe {
  240. gpgme_error_try(&lib, call!(&lib, gpgme_new)(&mut ptr))?;
  241. call!(&lib, gpgme_set_io_cbs)(ptr, &mut io_cbs);
  242. }
  243. let ret = Context {
  244. inner: Arc::new(ContextInner {
  245. inner: core::ptr::NonNull::new(ptr).ok_or_else(|| {
  246. MeliError::new("Could not use libgpgme").set_kind(ErrorKind::Bug)
  247. })?,
  248. lib,
  249. }),
  250. io_state,
  251. };
  252. ret.set_flag(GpgmeFlag::AutoKeyRetrieve, false)?;
  253. ret.set_flag(GpgmeFlag::OfflineMode, true)?;
  254. ret.set_flag(GpgmeFlag::AsciiArmor, true)?;
  255. ret.set_auto_key_locate(LocateKey::LOCAL)?;
  256. Ok(ret)
  257. }
  258. fn set_flag_inner(
  259. &self,
  260. raw_flag: *const ::std::os::raw::c_char,
  261. raw_value: *const ::std::os::raw::c_char,
  262. ) -> Result<()> {
  263. unsafe {
  264. gpgme_error_try(
  265. &self.inner.lib,
  266. call!(&self.inner.lib, gpgme_set_ctx_flag)(
  267. self.inner.inner.as_ptr(),
  268. raw_flag,
  269. raw_value,
  270. ),
  271. )?;
  272. }
  273. Ok(())
  274. }
  275. pub fn set_flag(&self, flag: GpgmeFlag, value: bool) -> Result<()> {
  276. match flag {
  277. GpgmeFlag::AutoKeyRetrieve => {}
  278. GpgmeFlag::OfflineMode => {
  279. unsafe {
  280. call!(&self.inner.lib, gpgme_set_offline)(
  281. self.inner.inner.as_ptr(),
  282. if value { 1 } else { 0 },
  283. );
  284. };
  285. return Ok(());
  286. }
  287. GpgmeFlag::AsciiArmor => {
  288. unsafe {
  289. call!(&self.inner.lib, gpgme_set_armor)(
  290. self.inner.inner.as_ptr(),
  291. if value { 1 } else { 0 },
  292. );
  293. };
  294. return Ok(());
  295. }
  296. };
  297. const VALUE_ON: &[u8; 2] = b"1\0";
  298. const VALUE_OFF: &[u8; 2] = b"0\0";
  299. let raw_flag = match flag {
  300. GpgmeFlag::AutoKeyRetrieve => c_string_literal!("auto-key-retrieve"),
  301. GpgmeFlag::AsciiArmor | GpgmeFlag::OfflineMode => unreachable!(),
  302. };
  303. self.set_flag_inner(
  304. raw_flag,
  305. if value { VALUE_ON } else { VALUE_OFF }.as_ptr() as *const ::std::os::raw::c_char,
  306. )
  307. }
  308. fn get_flag_inner(
  309. &self,
  310. raw_flag: *const ::std::os::raw::c_char,
  311. ) -> *const ::std::os::raw::c_char {
  312. unsafe { call!(&self.inner.lib, gpgme_get_ctx_flag)(self.inner.inner.as_ptr(), raw_flag) }
  313. }
  314. pub fn get_flag(&self, flag: GpgmeFlag) -> Result<bool> {
  315. let raw_flag = match flag {
  316. GpgmeFlag::AutoKeyRetrieve => c_string_literal!("auto-key-retrieve"),
  317. GpgmeFlag::OfflineMode => {
  318. return Ok(unsafe {
  319. call!(&self.inner.lib, gpgme_get_offline)(self.inner.inner.as_ptr()) > 0
  320. });
  321. }
  322. GpgmeFlag::AsciiArmor => {
  323. return Ok(unsafe {
  324. call!(&self.inner.lib, gpgme_get_armor)(self.inner.inner.as_ptr()) > 0
  325. });
  326. }
  327. };
  328. let val = self.get_flag_inner(raw_flag);
  329. Ok(!val.is_null())
  330. }
  331. pub fn set_auto_key_locate(&self, val: LocateKey) -> Result<()> {
  332. let auto_key_locate: *const ::std::os::raw::c_char = c_string_literal!("auto-key-locate");
  333. if val == LocateKey::NODEFAULT {
  334. self.set_flag_inner(auto_key_locate, c_string_literal!("clear,nodefault"))
  335. } else {
  336. let mut accum = val.to_string();
  337. accum.push('\0');
  338. self.set_flag_inner(
  339. auto_key_locate,
  340. CStr::from_bytes_with_nul(accum.as_bytes())
  341. .expect(accum.as_str())
  342. .as_ptr() as *const _,
  343. )
  344. }
  345. }
  346. pub fn get_auto_key_locate(&self) -> Result<LocateKey> {
  347. let auto_key_locate: *const ::std::os::raw::c_char = c_string_literal!("auto-key-locate");
  348. let raw_value =
  349. unsafe { CStr::from_ptr(self.get_flag_inner(auto_key_locate)) }.to_string_lossy();
  350. let mut val = LocateKey::NODEFAULT;
  351. if !raw_value.contains("nodefault") {
  352. for mechanism in raw_value.split(",") {
  353. match mechanism {
  354. "cert" => val.set(LocateKey::CERT, true),
  355. "pka" => {
  356. val.set(LocateKey::PKA, true);
  357. }
  358. "wkd" => {
  359. val.set(LocateKey::WKD, true);
  360. }
  361. "ldap" => {
  362. val.set(LocateKey::LDAP, true);
  363. }
  364. "keyserver" => {
  365. val.set(LocateKey::KEYSERVER, true);
  366. }
  367. "keyserver-url" => {
  368. val.set(LocateKey::KEYSERVER_URL, true);
  369. }
  370. "local" => {
  371. val.set(LocateKey::LOCAL, true);
  372. }
  373. unknown => {
  374. debug!("unknown mechanism: {}", unknown);
  375. }
  376. }
  377. }
  378. }
  379. Ok(val)
  380. }
  381. pub fn new_data_mem(&self, bytes: &[u8]) -> Result<Data> {
  382. let mut ptr = core::ptr::null_mut();
  383. unsafe {
  384. gpgme_error_try(
  385. &self.inner.lib,
  386. call!(&self.inner.lib, gpgme_data_new_from_mem)(
  387. &mut ptr,
  388. bytes.as_ptr() as *const ::std::os::raw::c_char,
  389. bytes.len(),
  390. 1,
  391. ),
  392. )?;
  393. }
  394. Ok(Data {
  395. lib: self.inner.lib.clone(),
  396. kind: DataKind::Memory,
  397. inner: core::ptr::NonNull::new(ptr).ok_or_else(|| {
  398. MeliError::new("Could not create libgpgme data").set_kind(ErrorKind::Bug)
  399. })?,
  400. })
  401. }
  402. pub fn new_data_file<P: AsRef<Path>>(&self, r: P) -> Result<Data> {
  403. let path: &Path = r.as_ref();
  404. if !path.exists() {
  405. return Err(MeliError::new(format!(
  406. "File `{}` doesn't exist.",
  407. path.display()
  408. )));
  409. }
  410. let os_str: &OsStr = path.as_ref();
  411. let b = CString::new(os_str.as_bytes())?;
  412. let mut ptr = core::ptr::null_mut();
  413. unsafe {
  414. let ret: GpgmeError = call!(&self.inner.lib, gpgme_data_new_from_file)(
  415. &mut ptr,
  416. b.as_ptr() as *const ::std::os::raw::c_char,
  417. 1,
  418. );
  419. gpgme_error_try(&self.inner.lib, ret)?;
  420. }
  421. Ok(Data {
  422. lib: self.inner.lib.clone(),
  423. kind: DataKind::Memory,
  424. inner: core::ptr::NonNull::new(ptr).ok_or_else(|| {
  425. MeliError::new("Could not create libgpgme data").set_kind(ErrorKind::Bug)
  426. })?,
  427. })
  428. }
  429. pub fn verify(
  430. &mut self,
  431. mut signature: Data,
  432. mut text: Data,
  433. ) -> Result<impl Future<Output = Result<()>> + Send> {
  434. unsafe {
  435. gpgme_error_try(
  436. &self.inner.lib,
  437. call!(&self.inner.lib, gpgme_op_verify_start)(
  438. self.inner.inner.as_ptr(),
  439. signature.inner.as_mut(),
  440. text.inner.as_mut(),
  441. std::ptr::null_mut(),
  442. ),
  443. )?;
  444. }
  445. let ctx = self.inner.clone();
  446. let io_state = self.io_state.clone();
  447. let io_state_lck = self.io_state.lock().unwrap();
  448. let done = io_state_lck.done.clone();
  449. let fut = io_state_lck
  450. .ops
  451. .values()
  452. .map(|a| Async::new(a.clone()).unwrap())
  453. .collect::<Vec<Async<GpgmeFd>>>();
  454. drop(io_state_lck);
  455. Ok(async move {
  456. let _s = signature;
  457. let _t = text;
  458. futures::future::join_all(fut.iter().map(|fut| {
  459. let done = done.clone();
  460. if fut.get_ref().write {
  461. futures::future::select(
  462. fut.get_ref().receiver.recv().boxed(),
  463. fut.write_with(move |_f| {
  464. if done.lock().unwrap().is_some() {
  465. return Ok(());
  466. }
  467. unsafe {
  468. (fut.get_ref().fnc.unwrap())(
  469. fut.get_ref().fnc_data,
  470. fut.get_ref().fd,
  471. )
  472. };
  473. if done.lock().unwrap().is_none() {
  474. return Err(std::io::ErrorKind::WouldBlock.into());
  475. }
  476. Ok(())
  477. })
  478. .boxed(),
  479. )
  480. .boxed()
  481. } else {
  482. futures::future::select(
  483. fut.get_ref().receiver.recv().boxed(),
  484. fut.read_with(move |_f| {
  485. if done.lock().unwrap().is_some() {
  486. return Ok(());
  487. }
  488. unsafe {
  489. (fut.get_ref().fnc.unwrap())(
  490. fut.get_ref().fnc_data,
  491. fut.get_ref().fd,
  492. )
  493. };
  494. if done.lock().unwrap().is_none() {
  495. return Err(std::io::ErrorKind::WouldBlock.into());
  496. }
  497. Ok(())
  498. })
  499. .boxed(),
  500. )
  501. .boxed()
  502. }
  503. }))
  504. .await;
  505. debug!("done with fut join");
  506. let rcv = {
  507. let io_state_lck = io_state.lock().unwrap();
  508. io_state_lck.receiver.clone()
  509. };
  510. let _ = rcv.recv().await;
  511. {
  512. let verify_result =
  513. unsafe { call!(&ctx.lib, gpgme_op_verify_result)(ctx.inner.as_ptr()) };
  514. if verify_result.is_null() {
  515. return Err(MeliError::new(
  516. "Unspecified libgpgme error: gpgme_op_verify_result returned NULL.",
  517. )
  518. .set_err_kind(ErrorKind::External));
  519. }
  520. drop(verify_result);
  521. }
  522. let io_state_lck = io_state.lock().unwrap();
  523. let ret = io_state_lck
  524. .done
  525. .lock()
  526. .unwrap()
  527. .take()
  528. .unwrap_or_else(|| Err(MeliError::new("Unspecified libgpgme error")));
  529. ret
  530. })
  531. }
  532. pub fn keylist(
  533. &mut self,
  534. secret: bool,
  535. pattern: Option<String>,
  536. ) -> Result<impl Future<Output = Result<Vec<Key>>>> {
  537. let pattern = if let Some(pattern) = pattern {
  538. Some(CString::new(pattern)?)
  539. } else {
  540. None
  541. };
  542. unsafe {
  543. gpgme_error_try(
  544. &self.inner.lib,
  545. call!(&self.inner.lib, gpgme_op_keylist_start)(
  546. self.inner.inner.as_ptr(),
  547. pattern
  548. .as_ref()
  549. .map(|cs| cs.as_ptr())
  550. .unwrap_or(std::ptr::null_mut())
  551. as *const ::std::os::raw::c_char,
  552. if secret { 1 } else { 0 },
  553. ),
  554. )?;
  555. }
  556. let ctx = self.inner.clone();
  557. let io_state = self.io_state.clone();
  558. let io_state_lck = self.io_state.lock().unwrap();
  559. let done = io_state_lck.done.clone();
  560. let fut = io_state_lck
  561. .ops
  562. .values()
  563. .map(|a| Async::new(a.clone()).unwrap())
  564. .collect::<Vec<Async<GpgmeFd>>>();
  565. drop(io_state_lck);
  566. Ok(async move {
  567. futures::future::join_all(fut.iter().map(|fut| {
  568. let done = done.clone();
  569. if fut.get_ref().write {
  570. futures::future::select(
  571. fut.get_ref().receiver.recv().boxed(),
  572. fut.write_with(move |_f| {
  573. if done.lock().unwrap().is_some() {
  574. return Ok(());
  575. }
  576. unsafe {
  577. (fut.get_ref().fnc.unwrap())(
  578. fut.get_ref().fnc_data,
  579. fut.get_ref().fd,
  580. )
  581. };
  582. if done.lock().unwrap().is_none() {
  583. return Err(std::io::ErrorKind::WouldBlock.into());
  584. }
  585. Ok(())
  586. })
  587. .boxed(),
  588. )
  589. .boxed()
  590. } else {
  591. futures::future::select(
  592. fut.get_ref().receiver.recv().boxed(),
  593. fut.read_with(move |_f| {
  594. if done.lock().unwrap().is_some() {
  595. return Ok(());
  596. }
  597. unsafe {
  598. (fut.get_ref().fnc.unwrap())(
  599. fut.get_ref().fnc_data,
  600. fut.get_ref().fd,
  601. )
  602. };
  603. if done.lock().unwrap().is_none() {
  604. return Err(std::io::ErrorKind::WouldBlock.into());
  605. }
  606. Ok(())
  607. })
  608. .boxed(),
  609. )
  610. .boxed()
  611. }
  612. }))
  613. .await;
  614. let (rcv, key_receiver) = {
  615. let io_state_lck = io_state.lock().unwrap();
  616. (
  617. io_state_lck.receiver.clone(),
  618. io_state_lck.key_receiver.clone(),
  619. )
  620. };
  621. let _ = rcv.recv().await;
  622. unsafe {
  623. gpgme_error_try(
  624. &ctx.lib,
  625. call!(&ctx.lib, gpgme_op_keylist_end)(ctx.inner.as_ptr()),
  626. )?;
  627. }
  628. let io_state_lck = io_state.lock().unwrap();
  629. io_state_lck
  630. .done
  631. .lock()
  632. .unwrap()
  633. .take()
  634. .unwrap_or_else(|| Err(MeliError::new("Unspecified libgpgme error")))?;
  635. let mut keys = vec![];
  636. while let Ok(inner) = key_receiver.try_recv() {
  637. let key = Key::new(inner, ctx.lib.clone());
  638. keys.push(key);
  639. }
  640. Ok(keys)
  641. })
  642. }
  643. pub fn sign(
  644. &mut self,
  645. sign_keys: Vec<Key>,
  646. mut text: Data,
  647. ) -> Result<impl Future<Output = Result<Vec<u8>>>> {
  648. if sign_keys.is_empty() {
  649. return Err(
  650. MeliError::new("gpgme: Call to sign() with zero keys.").set_kind(ErrorKind::Bug)
  651. );
  652. }
  653. let mut sig: gpgme_data_t = std::ptr::null_mut();
  654. unsafe {
  655. gpgme_error_try(
  656. &self.inner.lib,
  657. call!(&self.inner.lib, gpgme_data_new)(&mut sig),
  658. )?;
  659. call!(&self.inner.lib, gpgme_signers_clear)(self.inner.inner.as_ptr());
  660. for k in sign_keys {
  661. gpgme_error_try(
  662. &self.inner.lib,
  663. call!(&self.inner.lib, gpgme_signers_add)(
  664. self.inner.inner.as_ptr(),
  665. k.inner.inner.as_ptr(),
  666. ),
  667. )?;
  668. }
  669. }
  670. unsafe {
  671. gpgme_error_try(
  672. &self.inner.lib,
  673. call!(&self.inner.lib, gpgme_op_sign_start)(
  674. self.inner.inner.as_ptr(),
  675. text.inner.as_mut(),
  676. sig,
  677. gpgme_sig_mode_t_GPGME_SIG_MODE_DETACH,
  678. ),
  679. )?;
  680. }
  681. let mut sig = Data {
  682. lib: self.inner.lib.clone(),
  683. kind: DataKind::Memory,
  684. inner: core::ptr::NonNull::new(sig).ok_or_else(|| {
  685. MeliError::new("internal libgpgme error").set_kind(ErrorKind::Bug)
  686. })?,
  687. };
  688. let io_state = self.io_state.clone();
  689. let io_state_lck = self.io_state.lock().unwrap();
  690. let done = io_state_lck.done.clone();
  691. let fut = io_state_lck
  692. .ops
  693. .values()
  694. .map(|a| Async::new(a.clone()).unwrap())
  695. .collect::<Vec<Async<GpgmeFd>>>();
  696. drop(io_state_lck);
  697. Ok(async move {
  698. futures::future::join_all(fut.iter().map(|fut| {
  699. let done = done.clone();
  700. if fut.get_ref().write {
  701. futures::future::select(
  702. fut.get_ref().receiver.recv().boxed(),
  703. fut.write_with(move |_f| {
  704. if done.lock().unwrap().is_some() {
  705. return Ok(());
  706. }
  707. unsafe {
  708. (fut.get_ref().fnc.unwrap())(
  709. fut.get_ref().fnc_data,
  710. fut.get_ref().fd,
  711. )
  712. };
  713. if done.lock().unwrap().is_none() {
  714. return Err(std::io::ErrorKind::WouldBlock.into());
  715. }
  716. Ok(())
  717. })
  718. .boxed(),
  719. )
  720. .boxed()
  721. } else {
  722. futures::future::select(
  723. fut.get_ref().receiver.recv().boxed(),
  724. fut.read_with(move |_f| {
  725. if done.lock().unwrap().is_some() {
  726. return Ok(());
  727. }
  728. unsafe {
  729. (fut.get_ref().fnc.unwrap())(
  730. fut.get_ref().fnc_data,
  731. fut.get_ref().fd,
  732. )
  733. };
  734. if done.lock().unwrap().is_none() {
  735. return Err(std::io::ErrorKind::WouldBlock.into());
  736. }
  737. Ok(())
  738. })
  739. .boxed(),
  740. )
  741. .boxed()
  742. }
  743. }))
  744. .await;
  745. let rcv = {
  746. let io_state_lck = io_state.lock().unwrap();
  747. io_state_lck.receiver.clone()
  748. };
  749. let _ = rcv.recv().await;
  750. let io_state_lck = io_state.lock().unwrap();
  751. io_state_lck
  752. .done
  753. .lock()
  754. .unwrap()
  755. .take()
  756. .unwrap_or_else(|| Err(MeliError::new("Unspecified libgpgme error")))?;
  757. sig.seek(std::io::SeekFrom::Start(0))
  758. .chain_err_summary(|| {
  759. "libgpgme error: could not perform seek on signature data object"
  760. })?;
  761. Ok(sig.into_bytes()?)
  762. })
  763. }
  764. pub fn decrypt(
  765. &mut self,
  766. mut cipher: Data,
  767. ) -> Result<impl Future<Output = Result<(DecryptionMetadata, Vec<u8>)>> + Send> {
  768. let mut plain: gpgme_data_t = std::ptr::null_mut();
  769. unsafe {
  770. gpgme_error_try(
  771. &self.inner.lib,
  772. call!(&self.inner.lib, gpgme_data_new)(&mut plain),
  773. )?;
  774. gpgme_error_try(
  775. &self.inner.lib,
  776. call!(&self.inner.lib, gpgme_op_decrypt_start)(
  777. self.inner.inner.as_ptr(),
  778. cipher.inner.as_mut(),
  779. plain,
  780. ),
  781. )?;
  782. }
  783. let mut plain = Data {
  784. lib: self.inner.lib.clone(),
  785. kind: DataKind::Memory,
  786. inner: core::ptr::NonNull::new(plain).ok_or_else(|| {
  787. MeliError::new("internal libgpgme error").set_kind(ErrorKind::Bug)
  788. })?,
  789. };
  790. let ctx = self.inner.clone();
  791. let io_state = self.io_state.clone();
  792. let io_state_lck = self.io_state.lock().unwrap();
  793. let done = io_state_lck.done.clone();
  794. let fut = io_state_lck
  795. .ops
  796. .values()
  797. .map(|a| Async::new(a.clone()).unwrap())
  798. .collect::<Vec<Async<GpgmeFd>>>();
  799. drop(io_state_lck);
  800. Ok(async move {
  801. let _c = cipher;
  802. futures::future::join_all(fut.iter().map(|fut| {
  803. let done = done.clone();
  804. if fut.get_ref().write {
  805. futures::future::select(
  806. fut.get_ref().receiver.recv().boxed(),
  807. fut.write_with(move |_f| {
  808. if done.lock().unwrap().is_some() {
  809. return Ok(());
  810. }
  811. unsafe {
  812. (fut.get_ref().fnc.unwrap())(
  813. fut.get_ref().fnc_data,
  814. fut.get_ref().fd,
  815. )
  816. };
  817. if done.lock().unwrap().is_none() {
  818. return Err(std::io::ErrorKind::WouldBlock.into());
  819. }
  820. Ok(())
  821. })
  822. .boxed(),
  823. )
  824. .boxed()
  825. } else {
  826. futures::future::select(
  827. fut.get_ref().receiver.recv().boxed(),
  828. fut.read_with(move |_f| {
  829. if done.lock().unwrap().is_some() {
  830. return Ok(());
  831. }
  832. unsafe {
  833. (fut.get_ref().fnc.unwrap())(
  834. fut.get_ref().fnc_data,
  835. fut.get_ref().fd,
  836. )
  837. };
  838. if done.lock().unwrap().is_none() {
  839. return Err(std::io::ErrorKind::WouldBlock.into());
  840. }
  841. Ok(())
  842. })
  843. .boxed(),
  844. )
  845. .boxed()
  846. }
  847. }))
  848. .await;
  849. let rcv = {
  850. let io_state_lck = io_state.lock().unwrap();
  851. io_state_lck.receiver.clone()
  852. };
  853. let _ = rcv.recv().await;
  854. let io_state_lck = io_state.lock().unwrap();
  855. io_state_lck
  856. .done
  857. .lock()
  858. .unwrap()
  859. .take()
  860. .unwrap_or_else(|| Err(MeliError::new("Unspecified libgpgme error")))?;
  861. let decrypt_result =
  862. unsafe { call!(&ctx.lib, gpgme_op_decrypt_result)(ctx.inner.as_ptr()) };
  863. if decrypt_result.is_null() {
  864. return Err(MeliError::new(
  865. "Unspecified libgpgme error: gpgme_op_decrypt_result returned NULL.",
  866. )
  867. .set_err_kind(ErrorKind::External));
  868. }
  869. let mut recipients = vec![];
  870. let is_mime;
  871. let file_name;
  872. let session_key;
  873. unsafe {
  874. is_mime = (*decrypt_result).is_mime() > 0;
  875. file_name = if !(*decrypt_result).file_name.is_null() {
  876. Some(
  877. CStr::from_ptr((*decrypt_result).file_name)
  878. .to_string_lossy()
  879. .to_string(),
  880. )
  881. } else {
  882. None
  883. };
  884. session_key = if !(*decrypt_result).session_key.is_null() {
  885. Some(
  886. CStr::from_ptr((*decrypt_result).session_key)
  887. .to_string_lossy()
  888. .to_string(),
  889. )
  890. } else {
  891. None
  892. };
  893. let mut recipient_iter = (*decrypt_result).recipients;
  894. while !recipient_iter.is_null() {
  895. recipients.push(Recipient {
  896. keyid: if !(*recipient_iter).keyid.is_null() {
  897. Some(
  898. CStr::from_ptr((*recipient_iter).keyid)
  899. .to_string_lossy()
  900. .to_string(),
  901. )
  902. } else {
  903. None
  904. },
  905. status: gpgme_error_try(&ctx.lib, (*recipient_iter).status),
  906. });
  907. recipient_iter = (*recipient_iter).next;
  908. }
  909. }
  910. /* Rewind cursor */
  911. plain
  912. .seek(std::io::SeekFrom::Start(0))
  913. .chain_err_summary(|| "libgpgme error: could not perform seek on plain text")?;
  914. Ok((
  915. DecryptionMetadata {
  916. recipients,
  917. file_name,
  918. session_key,
  919. is_mime,
  920. },
  921. plain.into_bytes()?,
  922. ))
  923. })
  924. }
  925. pub fn encrypt(
  926. &mut self,
  927. sign_keys: Option<Vec<Key>>,
  928. encrypt_keys: Vec<Key>,
  929. mut plain: Data,
  930. ) -> Result<impl Future<Output = Result<Vec<u8>>> + Send> {
  931. if encrypt_keys.is_empty() {
  932. return Err(
  933. MeliError::new("gpgme: Call to encrypt() with zero keys.").set_kind(ErrorKind::Bug)
  934. );
  935. }
  936. unsafe {
  937. call!(&self.inner.lib, gpgme_signers_clear)(self.inner.inner.as_ptr());
  938. }
  939. let also_sign: bool = if let Some(keys) = sign_keys {
  940. if keys.is_empty() {
  941. false
  942. } else {
  943. for k in keys {
  944. unsafe {
  945. gpgme_error_try(
  946. &self.inner.lib,
  947. call!(&self.inner.lib, gpgme_signers_add)(
  948. self.inner.inner.as_ptr(),
  949. k.inner.inner.as_ptr(),
  950. ),
  951. )?;
  952. }
  953. }
  954. true
  955. }
  956. } else {
  957. false
  958. };
  959. let mut cipher: gpgme_data_t = std::ptr::null_mut();
  960. let mut raw_keys: Vec<gpgme_key_t> = Vec::with_capacity(encrypt_keys.len() + 1);
  961. raw_keys.extend(encrypt_keys.iter().map(|k| k.inner.inner.as_ptr()));
  962. raw_keys.push(std::ptr::null_mut());
  963. unsafe {
  964. gpgme_error_try(
  965. &self.inner.lib,
  966. call!(&self.inner.lib, gpgme_data_new)(&mut cipher),
  967. )?;
  968. gpgme_error_try(
  969. &self.inner.lib,
  970. if also_sign {
  971. call!(&self.inner.lib, gpgme_op_encrypt_sign_start)(
  972. self.inner.inner.as_ptr(),
  973. raw_keys.as_mut_ptr(),
  974. gpgme_encrypt_flags_t_GPGME_ENCRYPT_NO_ENCRYPT_TO
  975. | gpgme_encrypt_flags_t_GPGME_ENCRYPT_NO_COMPRESS,
  976. plain.inner.as_mut(),
  977. cipher,
  978. )
  979. } else {
  980. call!(&self.inner.lib, gpgme_op_encrypt_start)(
  981. self.inner.inner.as_ptr(),
  982. raw_keys.as_mut_ptr(),
  983. gpgme_encrypt_flags_t_GPGME_ENCRYPT_NO_ENCRYPT_TO
  984. | gpgme_encrypt_flags_t_GPGME_ENCRYPT_NO_COMPRESS,
  985. plain.inner.as_mut(),
  986. cipher,
  987. )
  988. },
  989. )?;
  990. }
  991. let mut cipher = Data {
  992. lib: self.inner.lib.clone(),
  993. kind: DataKind::Memory,
  994. inner: core::ptr::NonNull::new(cipher).ok_or_else(|| {
  995. MeliError::new("internal libgpgme error").set_kind(ErrorKind::Bug)
  996. })?,
  997. };
  998. let ctx = self.inner.clone();
  999. let io_state = self.io_state.clone();
  1000. let io_state_lck = self.io_state.lock().unwrap();
  1001. let done = io_state_lck.done.clone();
  1002. let fut = io_state_lck
  1003. .ops
  1004. .values()
  1005. .map(|a| Async::new(a.clone()).unwrap())
  1006. .collect::<Vec<Async<GpgmeFd>>>();
  1007. drop(io_state_lck);
  1008. Ok(async move {
  1009. futures::future::join_all(fut.iter().map(|fut| {
  1010. let done = done.clone();
  1011. if fut.get_ref().write {
  1012. futures::future::select(
  1013. fut.get_ref().receiver.recv().boxed(),
  1014. fut.write_with(move |_f| {
  1015. if done.lock().unwrap().is_some() {
  1016. return Ok(());
  1017. }
  1018. unsafe {
  1019. (fut.get_ref().fnc.unwrap())(
  1020. fut.get_ref().fnc_data,
  1021. fut.get_ref().fd,
  1022. )
  1023. };
  1024. if done.lock().unwrap().is_none() {
  1025. return Err(std::io::ErrorKind::WouldBlock.into());
  1026. }
  1027. Ok(())
  1028. })
  1029. .boxed(),
  1030. )
  1031. .boxed()
  1032. } else {
  1033. futures::future::select(
  1034. fut.get_ref().receiver.recv().boxed(),
  1035. fut.read_with(move |_f| {
  1036. if done.lock().unwrap().is_some() {
  1037. return Ok(());
  1038. }
  1039. unsafe {
  1040. (fut.get_ref().fnc.unwrap())(
  1041. fut.get_ref().fnc_data,
  1042. fut.get_ref().fd,
  1043. )
  1044. };
  1045. if done.lock().unwrap().is_none() {
  1046. return Err(std::io::ErrorKind::WouldBlock.into());
  1047. }
  1048. Ok(())
  1049. })
  1050. .boxed(),
  1051. )
  1052. .boxed()
  1053. }
  1054. }))
  1055. .await;
  1056. let rcv = {
  1057. let io_state_lck = io_state.lock().unwrap();
  1058. io_state_lck.receiver.clone()
  1059. };
  1060. let _ = rcv.recv().await;
  1061. let io_state_lck = io_state.lock().unwrap();
  1062. io_state_lck
  1063. .done
  1064. .lock()
  1065. .unwrap()
  1066. .take()
  1067. .unwrap_or_else(|| Err(MeliError::new("Unspecified libgpgme error")))?;
  1068. let encrypt_result =
  1069. unsafe { call!(&ctx.lib, gpgme_op_encrypt_result)(ctx.inner.as_ptr()) };
  1070. if encrypt_result.is_null() {
  1071. return Err(MeliError::new(
  1072. "Unspecified libgpgme error: gpgme_op_encrypt_result returned NULL.",
  1073. )
  1074. .set_err_kind(ErrorKind::External));
  1075. }
  1076. /* Rewind cursor */
  1077. cipher
  1078. .seek(std::io::SeekFrom::Start(0))
  1079. .chain_err_summary(|| "libgpgme error: could not perform seek on plain text")?;
  1080. Ok(cipher.into_bytes()?)
  1081. })
  1082. }
  1083. }
  1084. fn gpgme_error_try(lib: &libloading::Library, error_code: GpgmeError) -> Result<()> {
  1085. const ERR_MAX_LEN: usize = 256;
  1086. if error_code == 0 {
  1087. return Ok(());
  1088. }
  1089. let mut buf: Vec<u8> = vec![0; ERR_MAX_LEN];
  1090. unsafe {
  1091. call!(lib, gpgme_strerror_r)(
  1092. error_code,
  1093. buf.as_mut_ptr() as *mut ::std::os::raw::c_char,
  1094. ERR_MAX_LEN,
  1095. );
  1096. }
  1097. while buf.ends_with(&b"\0"[..]) {
  1098. buf.pop();
  1099. }
  1100. Err(MeliError::from(
  1101. String::from_utf8(buf)
  1102. .unwrap_or_else(|err| String::from_utf8_lossy(&err.into_bytes()).to_string()),
  1103. )
  1104. .set_summary(format!("libgpgme error {}", error_code)))
  1105. }
  1106. #[derive(Debug)]
  1107. enum DataKind {
  1108. Memory,
  1109. }
  1110. #[derive(Debug)]
  1111. pub struct Data {
  1112. inner: core::ptr::NonNull<bindings::gpgme_data>,
  1113. kind: DataKind,
  1114. lib: Arc<libloading::Library>,
  1115. }
  1116. impl Data {
  1117. pub fn into_bytes(mut self) -> Result<Vec<u8>> {
  1118. use std::io::Read;
  1119. let mut buf = vec![];
  1120. self.read_to_end(&mut buf)?;
  1121. Ok(buf)
  1122. }
  1123. }
  1124. unsafe impl Send for Data {}
  1125. unsafe impl Sync for Data {}
  1126. impl Drop for Data {
  1127. #[inline]
  1128. fn drop(&mut self) {
  1129. if !self.inner.as_ptr().is_null() {
  1130. match self.kind {
  1131. DataKind::Memory => unsafe {
  1132. call!(self.lib, gpgme_data_release)(self.inner.as_mut())
  1133. },
  1134. }
  1135. }
  1136. }
  1137. }
  1138. #[repr(C)]
  1139. #[derive(Clone)]
  1140. struct GpgmeFd {
  1141. fd: RawFd,
  1142. fnc: GpgmeIOCb,
  1143. fnc_data: *mut ::std::os::raw::c_void,
  1144. idx: usize,
  1145. write: bool,
  1146. sender: smol::channel::Sender<()>,
  1147. receiver: smol::channel::Receiver<()>,
  1148. io_state: Arc<Mutex<IoState>>,
  1149. }
  1150. unsafe impl Send for GpgmeFd {}
  1151. unsafe impl Sync for GpgmeFd {}
  1152. impl AsRawFd for GpgmeFd {
  1153. fn as_raw_fd(&self) -> RawFd {
  1154. self.fd
  1155. }
  1156. }
  1157. #[derive(Clone)]
  1158. struct KeyInner {
  1159. inner: core::ptr::NonNull<_gpgme_key>,
  1160. }
  1161. unsafe impl Send for KeyInner {}
  1162. unsafe impl Sync for KeyInner {}
  1163. pub struct Key {
  1164. inner: KeyInner,
  1165. lib: Arc<libloading::Library>,
  1166. }
  1167. unsafe impl Send for Key {}
  1168. unsafe impl Sync for Key {}
  1169. impl Clone for Key {
  1170. fn clone(&self) -> Self {
  1171. let lib = self.lib.clone();
  1172. unsafe {
  1173. call!(&self.lib, gpgme_key_ref)(self.inner.inner.as_ptr());
  1174. }
  1175. Key {
  1176. inner: self.inner.clone(),
  1177. lib,
  1178. }
  1179. }
  1180. }
  1181. impl Key {
  1182. #[inline(always)]
  1183. fn new(inner: KeyInner, lib: Arc<libloading::Library>) -> Self {
  1184. Key { inner, lib }
  1185. }
  1186. pub fn primary_uid(&self) -> Option<Address> {
  1187. unsafe {
  1188. if (*(self.inner.inner.as_ptr())).uids.is_null() {
  1189. return None;
  1190. }
  1191. let uid = (*(self.inner.inner.as_ptr())).uids;
  1192. if (*uid).name.is_null() && (*uid).email.is_null() {
  1193. None
  1194. } else if (*uid).name.is_null() {
  1195. Some(Address::new(
  1196. None,
  1197. CStr::from_ptr((*uid).email).to_string_lossy().to_string(),
  1198. ))
  1199. } else if (*uid).email.is_null() {
  1200. Some(Address::new(
  1201. None,
  1202. CStr::from_ptr((*uid).name).to_string_lossy().to_string(),
  1203. ))
  1204. } else {
  1205. Some(Address::new(
  1206. Some(CStr::from_ptr((*uid).name).to_string_lossy().to_string()),
  1207. CStr::from_ptr((*uid).email).to_string_lossy().to_string(),
  1208. ))
  1209. }
  1210. }
  1211. }
  1212. pub fn revoked(&self) -> bool {
  1213. unsafe { (*self.inner.inner.as_ptr()).revoked() > 0 }
  1214. }
  1215. pub fn expired(&self) -> bool {
  1216. unsafe { (*self.inner.inner.as_ptr()).expired() > 0 }
  1217. }
  1218. pub fn disabled(&self) -> bool {
  1219. unsafe { (*self.inner.inner.as_ptr()).disabled() > 0 }
  1220. }
  1221. pub fn invalid(&self) -> bool {
  1222. unsafe { (*self.inner.inner.as_ptr()).invalid() > 0 }
  1223. }
  1224. pub fn can_encrypt(&self) -> bool {
  1225. unsafe { (*self.inner.inner.as_ptr()).can_encrypt() > 0 }
  1226. }
  1227. pub fn can_sign(&self) -> bool {
  1228. unsafe { (*self.inner.inner.as_ptr()).can_sign() > 0 }
  1229. }
  1230. pub fn secret(&self) -> bool {
  1231. unsafe { (*self.inner.inner.as_ptr()).secret() > 0 }
  1232. }
  1233. pub fn fingerprint(&self) -> Cow<'_, str> {
  1234. (unsafe { CStr::from_ptr((*(self.inner.inner.as_ptr())).fpr) }).to_string_lossy()
  1235. }
  1236. }
  1237. impl std::fmt::Debug for Key {
  1238. fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
  1239. fmt.debug_struct("Key")
  1240. .field("fingerprint", &self.fingerprint())
  1241. .field("uid", &self.primary_uid())
  1242. .field("can_encrypt", &self.can_encrypt())
  1243. .field("can_sign", &self.can_sign())
  1244. .field("secret", &self.secret())
  1245. .field("revoked", &self.revoked())
  1246. .field("expired", &self.expired())
  1247. .field("invalid", &self.invalid())
  1248. .finish()
  1249. }
  1250. }
  1251. impl std::cmp::PartialEq for Key {
  1252. fn eq(&self, other: &Key) -> bool {
  1253. self.fingerprint() == other.fingerprint()
  1254. }
  1255. }
  1256. impl Drop for Key {
  1257. #[inline]
  1258. fn drop(&mut self) {
  1259. unsafe {
  1260. call!(&self.lib, gpgme_key_unref)(self.inner.inner.as_ptr());
  1261. }
  1262. }
  1263. }
  1264. //#[test]
  1265. //fn test_gpgme() {
  1266. // std::thread::spawn(move || {
  1267. // let ex = smol::Executor::new();
  1268. // futures::executor::block_on(ex.run(futures::future::pending::<()>()));
  1269. // });
  1270. // let mut ctx = Context::new().unwrap();
  1271. // //let sig = ctx.new_data_mem("sign").unwrap();
  1272. // //let text = ctx.new_data_mem("file").unwrap();
  1273. // let sig = ctx.new_data_mem(include_bytes!("/tmp/sig")).unwrap();
  1274. // let text = ctx.new_data_mem(include_bytes!("/tmp/data")).unwrap();
  1275. //
  1276. // futures::executor::block_on(ctx.verify(sig, text).unwrap()).unwrap();
  1277. // println!(
  1278. // "keys = {:#?}",
  1279. // futures::executor::block_on(ctx.keylist().unwrap()).unwrap()
  1280. // );
  1281. // let cipher = ctx.new_data_file("/tmp/msg.asc").unwrap();
  1282. // let plain = futures::executor::block_on(ctx.decrypt(cipher).unwrap()).unwrap();
  1283. // println!(
  1284. // "buf: {}",
  1285. // String::from_utf8_lossy(&plain.into_bytes().unwrap())
  1286. // );
  1287. //}