diff options
-rw-r--r-- | Cargo.lock | 1 | ||||
-rw-r--r-- | core/src/lib.rs | 153 | ||||
-rw-r--r-- | ffi/examples/configure.c | 4 | ||||
-rw-r--r-- | ffi/examples/keyserver.c | 2 | ||||
-rw-r--r-- | ffi/include/sequoia/core.h | 36 | ||||
-rw-r--r-- | ffi/include/sequoia/net.h | 32 | ||||
-rw-r--r-- | ffi/include/sequoia/store.h | 4 | ||||
-rw-r--r-- | ffi/src/core.rs | 19 | ||||
-rw-r--r-- | ffi/src/error.rs | 15 | ||||
-rw-r--r-- | ffi/src/net.rs | 27 | ||||
-rw-r--r-- | ffi/src/store.rs | 4 | ||||
-rw-r--r-- | net/Cargo.toml | 1 | ||||
-rw-r--r-- | net/src/lib.rs | 166 | ||||
-rw-r--r-- | net/tests/hkp.rs | 18 | ||||
-rw-r--r-- | sq/src/sq.rs | 35 | ||||
-rw-r--r-- | store/src/backend/mod.rs | 68 | ||||
-rw-r--r-- | store/src/lib.rs | 173 | ||||
-rw-r--r-- | store/tests/ipc-policy.rs | 17 |
18 files changed, 365 insertions, 410 deletions
@@ -1993,7 +1993,6 @@ dependencies = [ "native-tls", "percent-encoding", "rand", - "sequoia-core", "sequoia-openpgp", "tempfile", "thiserror", diff --git a/core/src/lib.rs b/core/src/lib.rs index 904facc1..b160161f 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -21,7 +21,6 @@ use dirs; use tempfile; -use std::fmt; use std::io; use std::path::{Path, PathBuf}; @@ -45,12 +44,12 @@ use std::path::{Path, PathBuf}; /// `Context::configure`: /// /// ``` -/// # use sequoia_core::{Context, NetworkPolicy, Result}; +/// # use sequoia_core::{Context, IPCPolicy, Result}; /// # f().unwrap(); /// # fn f() -> Result<()> { /// let c = Context::configure() /// # .ephemeral() -/// .network_policy(NetworkPolicy::Offline) +/// .ipc_policy(IPCPolicy::Robust) /// .build()?; /// # Ok(()) /// # } @@ -58,7 +57,6 @@ use std::path::{Path, PathBuf}; pub struct Context { home: PathBuf, lib: PathBuf, - network_policy: NetworkPolicy, ipc_policy: IPCPolicy, ephemeral: bool, cleanup: bool, @@ -69,7 +67,6 @@ impl Clone for Context { Context { home: self.home.clone(), lib: self.lib.clone(), - network_policy: self.network_policy, ipc_policy: self.ipc_policy, ephemeral: self.ephemeral, cleanup: false, // Prevent cleanup. @@ -108,7 +105,6 @@ impl Context { Config(Context { home: PathBuf::from(""), // Defer computation of default. lib: prefix().join("lib").join("sequoia"), - network_policy: NetworkPolicy::Encrypted, ipc_policy: IPCPolicy::Robust, ephemeral: false, cleanup: false, @@ -125,11 +121,6 @@ impl Context { &self.lib } - /// Returns the network policy. - pub fn network_policy(&self) -> &NetworkPolicy { - &self.network_policy - } - /// Returns the IPC policy. pub fn ipc_policy(&self) -> &IPCPolicy { &self.ipc_policy @@ -147,12 +138,12 @@ impl Context { /// `Context::configure`: /// /// ``` -/// # use sequoia_core::{Context, NetworkPolicy, Result}; +/// # use sequoia_core::{Context, IPCPolicy, Result}; /// # f().unwrap(); /// # fn f() -> Result<()> { /// let c = Context::configure() /// # .ephemeral() -/// .network_policy(NetworkPolicy::Offline) +/// .ipc_policy(IPCPolicy::Robust) /// .build()?; /// # Ok(()) /// # } @@ -226,18 +217,6 @@ impl Config { ::std::mem::replace(&mut self.0.lib, PathBuf::new().join(lib)) } - /// Sets the network policy. - pub fn network_policy(mut self, policy: NetworkPolicy) -> Self { - self.set_network_policy(policy); - self - } - - /// Sets the network policy. - pub fn set_network_policy(&mut self, policy: NetworkPolicy) -> NetworkPolicy - { - ::std::mem::replace(&mut self.0.network_policy, policy) - } - /// Sets the IPC policy. pub fn ipc_policy(mut self, policy: IPCPolicy) -> Self { self.set_ipc_policy(policy); @@ -269,84 +248,11 @@ pub type Result<T> = ::std::result::Result<T, anyhow::Error>; #[derive(thiserror::Error, Debug)] /// Errors for Sequoia. pub enum Error { - /// The network policy was violated by the given action. - #[error("Unmet network policy requirement: {0}")] - NetworkPolicyViolation(NetworkPolicy), - /// An `io::Error` occurred. #[error("{0}")] IoError(#[from] io::Error), } -/* Network policy. */ - -/// Network policy for Sequoia. -/// -/// With this policy you can control how Sequoia accesses remote -/// systems. -#[derive(PartialEq, PartialOrd, Debug, Copy, Clone)] -pub enum NetworkPolicy { - /// Do not contact remote systems. - Offline, - - /// Only contact remote systems using anonymization techniques - /// like TOR. - Anonymized, - - /// Only contact remote systems using transports offering - /// encryption and authentication like TLS. - Encrypted, - - /// Contact remote systems even with insecure transports. - Insecure, -} - -impl fmt::Display for NetworkPolicy { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", match self { - &NetworkPolicy::Offline => "Offline", - &NetworkPolicy::Anonymized => "Anonymized", - &NetworkPolicy::Encrypted => "Encrypted", - &NetworkPolicy::Insecure => "Insecure", - }) - } -} - -impl NetworkPolicy { - pub fn assert(&self, action: NetworkPolicy) -> Result<()> { - if action > *self { - Err(Error::NetworkPolicyViolation(action).into()) - } else { - Ok(()) - } - } -} - -impl<'a> From<&'a NetworkPolicy> for u8 { - fn from(policy: &NetworkPolicy) -> Self { - match policy { - &NetworkPolicy::Offline => 0, - &NetworkPolicy::Anonymized => 1, - &NetworkPolicy::Encrypted => 2, - &NetworkPolicy::Insecure => 3, - } - } -} - - -// XXX: TryFrom would be nice. -impl From<u8> for NetworkPolicy { - fn from(policy: u8) -> Self { - match policy { - 0 => NetworkPolicy::Offline, - 1 => NetworkPolicy::Anonymized, - 2 => NetworkPolicy::Encrypted, - 3 => NetworkPolicy::Insecure, - n => panic!("Bad network policy: {}", n), - } - } -} - /* IPC policy. */ /// IPC policy for Sequoia. @@ -435,54 +341,3 @@ macro_rules! assert_match { } }; } - -#[cfg(test)] -mod test { - use super::{Error, NetworkPolicy}; - - fn ok(policy: NetworkPolicy, required: NetworkPolicy) { - assert!(policy.assert(required).is_ok()); - } - - fn fail(policy: NetworkPolicy, required: NetworkPolicy) { - assert_match!(Error::NetworkPolicyViolation(_) - = policy.assert(required) - .err().unwrap().downcast::<Error>().unwrap()); - } - - #[test] - fn offline() { - let p = NetworkPolicy::Offline; - ok(p, NetworkPolicy::Offline); - fail(p, NetworkPolicy::Anonymized); - fail(p, NetworkPolicy::Encrypted); - fail(p, NetworkPolicy::Insecure); - } - - #[test] - fn anonymized() { - let p = NetworkPolicy::Anonymized; - ok(p, NetworkPolicy::Offline); - ok(p, NetworkPolicy::Anonymized); - fail(p, NetworkPolicy::Encrypted); - fail(p, NetworkPolicy::Insecure); - } - - #[test] - fn encrypted() { - let p = NetworkPolicy::Encrypted; - ok(p, NetworkPolicy::Offline); - ok(p, NetworkPolicy::Anonymized); - ok(p, NetworkPolicy::Encrypted); - fail(p, NetworkPolicy::Insecure); - } - - #[test] - fn insecure() { - let p = NetworkPolicy::Insecure; - ok(p, NetworkPolicy::Offline); - ok(p, NetworkPolicy::Anonymized); - ok(p, NetworkPolicy::Encrypted); - ok(p, NetworkPolicy::Insecure); - } -} diff --git a/ffi/examples/configure.c b/ffi/examples/configure.c index ca3d781a..6551e196 100644 --- a/ffi/examples/configure.c +++ b/ffi/examples/configure.c @@ -25,13 +25,13 @@ main (int argc, char **argv) sq_keyserver_t ks; cfg = sq_context_configure (); - sq_config_network_policy (cfg, SQ_NETWORK_POLICY_OFFLINE); + sq_config_home (cfg, "/tmp"); ctx = sq_config_build (cfg, &err); if (ctx == NULL) error (1, 0, "Initializing sequoia failed: %s", pgp_error_to_string (err)); - ks = sq_keyserver_keys_openpgp_org (ctx); + ks = sq_keyserver_keys_openpgp_org (ctx, SQ_NETWORK_POLICY_OFFLINE); if (ks == NULL) { pgp_error_t err = sq_context_last_error (ctx); diff --git a/ffi/examples/keyserver.c b/ffi/examples/keyserver.c index 64c90cdc..08624ea7 100644 --- a/ffi/examples/keyserver.c +++ b/ffi/examples/keyserver.c @@ -29,7 +29,7 @@ main (int argc, char **argv) error (1, 0, "Initializing sequoia failed: %s", pgp_error_to_string (err)); - ks = sq_keyserver_keys_openpgp_org (ctx); + ks = sq_keyserver_keys_openpgp_org (ctx, SQ_NETWORK_POLICY_ENCRYPTED); if (ks == NULL) { pgp_error_t err = sq_context_last_error (ctx); diff --git a/ffi/include/sequoia/core.h b/ffi/include/sequoia/core.h index c7f73f45..c73d54c1 100644 --- a/ffi/include/sequoia/core.h +++ b/ffi/include/sequoia/core.h @@ -33,32 +33,6 @@ pgp_error_t sq_context_last_error (sq_context_t ctx); typedef struct sq_config *sq_config_t; /*/ -/// Network policy for Sequoia. -/// -/// With this policy you can control how Sequoia accesses remote -/// systems. -/*/ -typedef enum sq_network_policy { - /* Do not contact remote systems. */ - SQ_NETWORK_POLICY_OFFLINE = 0, - - /* Only contact remote systems using anonymization techniques like - * TOR. */ - SQ_NETWORK_POLICY_ANONYMIZED = 1, - - /* Only contact remote systems using transports offering - * encryption and authentication like TLS. */ - SQ_NETWORK_POLICY_ENCRYPTED = 2, - - /* Contact remote systems even with insecure transports. */ - SQ_NETWORK_POLICY_INSECURE = 3, - - /* Dummy value to make sure the enumeration has a defined size. Do - not use this value. */ - SQ_NETWORK_POLICY_FORCE_WIDTH = INT_MAX, -} sq_network_policy_t; - -/*/ /// IPC policy for Sequoia. /// /// With this policy you can control how Sequoia starts background @@ -155,11 +129,6 @@ const char *sq_context_home(const sq_context_t ctx); const char *sq_context_lib(const sq_context_t ctx); /*/ -/// Returns the network policy. -/*/ -sq_network_policy_t sq_context_network_policy(const sq_context_t ctx); - -/*/ /// Returns the IPC policy. /*/ sq_ipc_policy_t sq_context_ipc_policy(const sq_context_t ctx); @@ -191,11 +160,6 @@ void sq_config_home(sq_config_t cfg, const char *home); void sq_config_lib(sq_config_t cfg, const char *lib); /*/ -/// Sets the network policy. -/*/ -void sq_config_network_policy(sq_config_t cfg, sq_network_policy_t policy); - -/*/ /// Sets the IPC policy. /*/ void sq_config_ipc_policy(sq_config_t cfg, sq_ipc_policy_t policy); diff --git a/ffi/include/sequoia/net.h b/ffi/include/sequoia/net.h index 63311d85..f1d850d3 100644 --- a/ffi/include/sequoia/net.h +++ b/ffi/include/sequoia/net.h @@ -9,6 +9,33 @@ typedef struct sq_keyserver *sq_keyserver_t; /*/ +/// Network policy for Sequoia. +/// +/// With this policy you can control how Sequoia accesses remote +/// systems. +/*/ +typedef enum sq_network_policy { + /* Do not contact remote systems. */ + SQ_NETWORK_POLICY_OFFLINE = 0, + + /* Only contact remote systems using anonymization techniques like + * TOR. */ + SQ_NETWORK_POLICY_ANONYMIZED = 1, + + /* Only contact remote systems using transports offering + * encryption and authentication like TLS. */ + SQ_NETWORK_POLICY_ENCRYPTED = 2, + + /* Contact remote systems even with insecure transports. */ + SQ_NETWORK_POLICY_INSECURE = 3, + + /* Dummy value to make sure the enumeration has a defined size. Do + not use this value. */ + SQ_NETWORK_POLICY_FORCE_WIDTH = INT_MAX, +} sq_network_policy_t; + + +/*/ /// Returns a handle for the given URI. /// /// `uri` is a UTF-8 encoded value of a keyserver URI, @@ -17,6 +44,7 @@ typedef struct sq_keyserver *sq_keyserver_t; /// Returns `NULL` on errors. /*/ sq_keyserver_t sq_keyserver_new (sq_context_t ctx, + sq_network_policy_t policy, const char *uri); /*/ @@ -29,6 +57,7 @@ sq_keyserver_t sq_keyserver_new (sq_context_t ctx, /// Returns `NULL` on errors. /*/ sq_keyserver_t sq_keyserver_with_cert (sq_context_t ctx, + sq_network_policy_t policy, const char *uri, const uint8_t *cert, size_t len); @@ -41,7 +70,8 @@ sq_keyserver_t sq_keyserver_with_cert (sq_context_t ctx, /// /// Returns `NULL` on errors. /*/ -sq_keyserver_t sq_keyserver_keys_openpgp_org (sq_context_t ctx); +sq_keyserver_t sq_keyserver_keys_openpgp_org (sq_context_t ctx, + sq_network_policy_t policy); /*/ /// Frees a keyserver object. diff --git a/ffi/include/sequoia/store.h b/ffi/include/sequoia/store.h index 694aa32c..5fc84d19 100644 --- a/ffi/include/sequoia/store.h +++ b/ffi/include/sequoia/store.h @@ -2,6 +2,7 @@ #define SEQUOIA_STORE_H #include <sequoia/core.h> +#include <sequoia/net.h> /*/ /// Keys used for communications. @@ -262,7 +263,8 @@ sq_key_iter_t sq_store_list_keys (sq_context_t ctx); /// Opening the mapping with a different network policy is /// forbidden. /*/ -sq_mapping_t sq_mapping_open (sq_context_t ctx, const char *realm, const char *name); +sq_mapping_t sq_mapping_open (sq_context_t ctx, sq_network_policy_t policy, + const char *realm, const char *name); /*/ /// Adds a key identified by fingerprint to the mapping. diff --git a/ffi/src/core.rs b/ffi/src/core.rs index 3051b133..d0dd5138 100644 --- a/ffi/src/core.rs +++ b/ffi/src/core.rs @@ -30,7 +30,7 @@ //! sq_context_t ctx; //! //! cfg = sq_context_configure (); -//! sq_config_network_policy (cfg, SQ_NETWORK_POLICY_OFFLINE); +//! sq_config_ipc_policy (cfg, SQ_IPC_POLICY_ROBUST); //! ctx = sq_config_build (cfg, NULL); //! //! /* Use Sequoia. */ @@ -111,13 +111,6 @@ fn sq_context_lib(ctx: *const Context) -> *const c_char { ctx.c.lib().to_string_lossy().as_bytes().as_ptr() as *const c_char } -/// Returns the network policy. -#[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" -fn sq_context_network_policy(ctx: *const Context) -> c_int { - let ctx = ffi_param_ref!(ctx); - u8::from(ctx.c.network_policy()) as c_int -} - /// Returns the IPC policy. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn sq_context_ipc_policy(ctx: *const Context) -> c_int { @@ -164,16 +157,6 @@ fn sq_config_lib(cfg: *mut Config, lib: *const c_char) { cfg.set_lib(&lib.as_ref()); } -/// Sets the network policy. -#[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" -fn sq_config_network_policy(cfg: *mut Config, policy: c_int) { - let cfg = ffi_param_ref_mut!(cfg); - if policy < 0 || policy > 3 { - panic!("Bad network policy: {}", policy); - } - cfg.set_network_policy((policy as u8).into()); -} - /// Sets the IPC policy. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn sq_config_ipc_policy(cfg: *mut Config, policy: c_int) { diff --git a/ffi/src/error.rs b/ffi/src/error.rs index 0eff9226..ebce4e0d 100644 --- a/ffi/src/error.rs +++ b/ffi/src/error.rs @@ -4,6 +4,7 @@ use std::io; use sequoia_openpgp as openpgp; use sequoia_core as core; +use sequoia_net as net; pub use crate::openpgp::error::Status; pub(crate) use crate::openpgp::error::Error; @@ -16,13 +17,23 @@ impl<'a> FromSequoiaError<'a> for Status { fn from_sequoia_error(e: &'a anyhow::Error) -> Self { if let Some(e) = e.downcast_ref::<core::Error>() { return match e { - &core::Error::NetworkPolicyViolation(_) => - Status::NetworkPolicyViolation, &core::Error::IoError(_) => Status::IoError, } } + if let Some(e) = e.downcast_ref::<net::Error>() { + return match e { + net::Error::PolicyViolation(_) => + Status::NetworkPolicyViolation, + e => { + // XXX + eprintln!("ffi: net error not converted: {}", e); + Status::UnknownError + }, + } + } + if let Some(e) = e.downcast_ref::<openpgp::Error>() { return match e { &openpgp::Error::InvalidArgument(_) => diff --git a/ffi/src/net.rs b/ffi/src/net.rs index 60154838..f08a3ef0 100644 --- a/ffi/src/net.rs +++ b/ffi/src/net.rs @@ -6,12 +6,10 @@ //! //! # Examples //! -//! We provide a very reasonable default key server backed by -//! `hkps.pool.sks-keyservers.net`, the subset of the [SKS keyserver] -//! network that uses https to protect integrity and confidentiality -//! of the communication with the client: +//! As reasonable default key server we provide a shortcut to use +//! [`keys.openpgp.org`]: //! -//! [SKS keyserver]: https://www.sks-keyservers.net/overview-of-pools.php#pool_hkps +//! [`keys.openpgp.org`]: https://keys.openpgp.org //! //! ```c //! #include <sequoia.h> @@ -22,7 +20,7 @@ //! pgp_cert_t cert; //! //! ctx = sq_context_new (NULL); -//! ks = sq_keyserver_keys_openpgp_org (ctx); +//! ks = sq_keyserver_keys_openpgp_org (ctx, SQ_NETWORK_POLICY_ENCRYPTED); //! id = pgp_keyid_from_bytes ((uint8_t *) "\x24\x7F\x6D\xAB\xC8\x49\x14\xFE"); //! cert = sq_keyserver_get (ctx, ks, id); //! @@ -54,12 +52,14 @@ use crate::Maybe; /// /// Returns `NULL` on errors. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" -fn sq_keyserver_new(ctx: *mut Context, uri: *const c_char) -> *mut KeyServer { +fn sq_keyserver_new(ctx: *mut Context, policy: u8, uri: *const c_char) + -> *mut KeyServer { let ctx = ffi_param_ref_mut!(ctx); ffi_make_fry_from_ctx!(ctx); + let policy = policy.into(); let uri = ffi_param_cstr!(uri).to_string_lossy(); - ffi_try_box!(KeyServer::new(&ctx.c, &uri)) + ffi_try_box!(KeyServer::new(policy, &uri)) } /// Returns a handle for the given URI. @@ -70,12 +70,13 @@ fn sq_keyserver_new(ctx: *mut Context, uri: *const c_char) -> *mut KeyServer { /// /// Returns `NULL` on errors. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" -fn sq_keyserver_with_cert(ctx: *mut Context, +fn sq_keyserver_with_cert(ctx: *mut Context, policy: u8, uri: *const c_char, cert: *const u8, len: size_t) -> *mut KeyServer { let ctx = ffi_param_ref_mut!(ctx); ffi_make_fry_from_ctx!(ctx); + let policy = policy.into(); let uri = ffi_param_cstr!(uri).to_string_lossy(); if cert.is_null() { @@ -88,7 +89,7 @@ fn sq_keyserver_with_cert(ctx: *mut Context, let cert = ffi_try!(Certificate::from_der(cert) .map_err(|e| ::anyhow::Error::from(e))); - ffi_try_box!(KeyServer::with_cert(&ctx.c, &uri, cert)) + ffi_try_box!(KeyServer::with_cert(policy, &uri, cert)) } /// Returns a handle for keys.openpgp.org. @@ -98,10 +99,12 @@ fn sq_keyserver_with_cert(ctx: *mut Context, /// /// Returns `NULL` on errors. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" -fn sq_keyserver_keys_openpgp_org(ctx: *mut Context) -> *mut KeyServer { +fn sq_keyserver_keys_openpgp_org(ctx: *mut Context, policy: u8) + -> *mut KeyServer { let ctx = ffi_param_ref_mut!(ctx); ffi_make_fry_from_ctx!(ctx); - ffi_try_box!(KeyServer::keys_openpgp_org(&ctx.c)) + let policy = policy.into(); + ffi_try_box!(KeyServer::keys_openpgp_org(policy)) } /// Frees a keyserver object. diff --git a/ffi/src/store.rs b/ffi/src/store.rs index 482f0dec..65372d78 100644 --- a/ffi/src/store.rs +++ b/ffi/src/store.rs @@ -190,15 +190,17 @@ fn sq_log_iter_free(iter: Option<&mut LogIter>) { /// forbidden. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" fn sq_mapping_open(ctx: *mut Context, + policy: u8, realm: *const c_char, name: *const c_char) -> *mut Mapping { let ctx = ffi_param_ref_mut!(ctx); ffi_make_fry_from_ctx!(ctx); + let policy = policy.into(); let realm = ffi_param_cstr!(realm).to_string_lossy(); let name = ffi_param_cstr!(name).to_string_lossy(); - ffi_try_box!(Mapping::open(&ctx.c, &realm, &name)) + ffi_try_box!(Mapping::open(&ctx.c, policy, &realm, &name)) } /// Frees a sq_mapping_t. diff --git a/net/Cargo.toml b/net/Cargo.toml index 307a65f0..cff91a70 100644 --- a/net/Cargo.toml +++ b/net/Cargo.toml @@ -22,7 +22,6 @@ maintenance = { status = "actively-developed" } [dependencies] sequoia-openpgp = { path = "../openpgp", version = "1.0.0", default-features = false } -sequoia-core = { path = "../core", version = "0.22" } anyhow = "1.0.18" futures-util = "0.3.5" diff --git a/net/src/lib.rs b/net/src/lib.rs index fa5b1659..dda95da8 100644 --- a/net/src/lib.rs +++ b/net/src/lib.rs @@ -15,11 +15,9 @@ //! //! ```no_run //! # use sequoia_openpgp::KeyID; -//! # use sequoia_core::Context; -//! # use sequoia_net::{KeyServer, Result}; +//! # use sequoia_net::{KeyServer, Policy, Result}; //! # async fn f() -> Result<()> { -//! let ctx = Context::new()?; -//! let mut ks = KeyServer::keys_openpgp_org(&ctx)?; +//! let mut ks = KeyServer::keys_openpgp_org(Policy::Encrypted)?; //! let keyid: KeyID = "31855247603831FD".parse()?; //! println!("{:?}", ks.get(keyid).await?); //! # Ok(()) @@ -36,6 +34,7 @@ use native_tls::{Certificate, TlsConnector}; use percent_encoding::{percent_encode, AsciiSet, CONTROLS}; use std::convert::From; +use std::fmt; use std::io::Cursor; use url::Url; @@ -48,7 +47,6 @@ use openpgp::{ parse::Parse, serialize::Serialize, }; -use sequoia_core::{Context, NetworkPolicy}; pub mod wkd; @@ -61,6 +59,75 @@ const KEYSERVER_ENCODE_SET: &AsciiSet = // respect to the encoding. .add(b'-').add(b'+').add(b'/'); +/// Network policy for Sequoia. +/// +/// With this policy you can control how Sequoia accesses remote +/// systems. +#[derive(PartialEq, PartialOrd, Debug, Copy, Clone)] +pub enum Policy { + /// Do not contact remote systems. + Offline, + + /// Only contact remote systems using anonymization techniques + /// like TOR. + Anonymized, + + /// Only contact remote systems using transports offering + /// encryption and authentication like TLS. + Encrypted, + + /// Contact remote systems even with insecure transports. + Insecure, +} + +impl fmt::Display for Policy { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", match self { + &Policy::Offline => "Offline", + &Policy::Anonymized => "Anonymized", + &Policy::Encrypted => "Encrypted", + &Policy::Insecure => "Insecure", + }) + } +} + +impl Policy { + /// Asserts that this policy allows an action requiring policy + /// `action`. + pub fn assert(&self, action: Policy) -> Result<()> { + if action > *self { + Err(Error::PolicyViolation(action).into()) + } else { + Ok(()) + } + } +} + +impl<'a> From<&'a Policy> for u8 { + fn from(policy: &Policy) -> Self { + match policy { + &Policy::Offline => 0, + &Policy::Anonymized => 1, + &Policy::Encrypted => 2, + &Policy::Insecure => 3, + } + } +} + + +// XXX: TryFrom would be nice. +impl From<u8> for Policy { + fn from(policy: u8) -> Self { + match policy { + 0 => |