summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/src/lib.rs114
-rw-r--r--ffi/src/lib.rs29
-rw-r--r--ffi/src/sequoia.h32
-rw-r--r--net/src/lib.rs24
4 files changed, 192 insertions, 7 deletions
diff --git a/core/src/lib.rs b/core/src/lib.rs
index 12085a11..1ac45c33 100644
--- a/core/src/lib.rs
+++ b/core/src/lib.rs
@@ -30,6 +30,7 @@ pub struct Context {
domain: String,
home: PathBuf,
lib: PathBuf,
+ network_policy: NetworkPolicy,
}
/// Returns $PREXIX, or a reasonable default prefix.
@@ -63,6 +64,7 @@ impl Context {
home: env::home_dir().unwrap_or(env::temp_dir())
.join(".sequoia"),
lib: prefix().join("lib").join("sequoia"),
+ network_policy: NetworkPolicy::Encrypted,
})
}
@@ -80,6 +82,12 @@ impl Context {
pub fn lib(&self) -> &Path {
&self.lib
}
+
+ /// Returns the network policy.
+ pub fn network_policy(&self) -> &NetworkPolicy {
+ &self.network_policy
+ }
+
}
/// Represents a `Context` configuration.
@@ -124,6 +132,17 @@ impl Config {
pub fn set_lib<P: AsRef<Path>>(&mut self, lib: P) {
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) {
+ self.0.network_policy = policy;
+ }
}
/* Error handling. */
@@ -134,6 +153,8 @@ pub type Result<T> = ::std::result::Result<T, Error>;
/// Errors for Sequoia.
#[derive(Debug)]
pub enum Error {
+ /// The network policy was violated by the given action.
+ NetworkPolicyViolation(NetworkPolicy),
/// An `io::Error` occured.
IoError(io::Error),
}
@@ -143,3 +164,96 @@ impl From<io::Error> for Error {
Error::IoError(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 NetworkPolicy {
+ pub fn assert(&self, action: NetworkPolicy) -> Result<()> {
+ if action > *self {
+ Err(Error::NetworkPolicyViolation(action))
+ } else {
+ Ok(())
+ }
+ }
+}
+
+#[cfg(test)]
+mod network_policy_test {
+ use super::{Error, NetworkPolicy};
+
+ macro_rules! assert_match {
+ ( $result:expr, $error: pat ) => {
+ if let $error = $result {
+ /* Pass. */
+ } else {
+ panic!("Expected {}, got {:?}.", stringify!($error), $result);
+ }
+ };
+ }
+
+
+ #[test]
+ fn offline() {
+ let p = NetworkPolicy::Offline;
+ assert_match!(p.assert(NetworkPolicy::Anonymized),
+ Err(Error::NetworkPolicyViolation(_)));
+ assert_match!(p.assert(NetworkPolicy::Encrypted),
+ Err(Error::NetworkPolicyViolation(_)));
+ assert_match!(p.assert(NetworkPolicy::Insecure),
+ Err(Error::NetworkPolicyViolation(_)));
+ }
+
+ #[test]
+ fn anonymized() {
+ let p = NetworkPolicy::Anonymized;
+ assert_match!(p.assert(NetworkPolicy::Anonymized),
+ Ok(()));
+ assert_match!(p.assert(NetworkPolicy::Encrypted),
+ Err(Error::NetworkPolicyViolation(_)));
+ assert_match!(p.assert(NetworkPolicy::Insecure),
+ Err(Error::NetworkPolicyViolation(_)));
+ }
+
+ #[test]
+ fn encrypted() {
+ let p = NetworkPolicy::Encrypted;
+ assert_match!(p.assert(NetworkPolicy::Anonymized),
+ Ok(()));
+ assert_match!(p.assert(NetworkPolicy::Encrypted),
+ Ok(()));
+ assert_match!(p.assert(NetworkPolicy::Insecure),
+ Err(Error::NetworkPolicyViolation(_)));
+ }
+
+ #[test]
+ fn insecure() {
+ let p = NetworkPolicy::Insecure;
+ assert_match!(p.assert(NetworkPolicy::Anonymized),
+ Ok(()));
+ assert_match!(p.assert(NetworkPolicy::Encrypted),
+ Ok(()));
+ assert_match!(p.assert(NetworkPolicy::Insecure),
+ Ok(()));
+ }
+}
diff --git a/ffi/src/lib.rs b/ffi/src/lib.rs
index b4f20eee..7ba09b10 100644
--- a/ffi/src/lib.rs
+++ b/ffi/src/lib.rs
@@ -42,7 +42,7 @@ use openpgp::tpk::TPK;
use openpgp::types::KeyId;
use self::libc::{uint8_t, uint64_t, c_char, size_t};
use self::native_tls::Certificate;
-use sequoia_core::{Config, Context};
+use sequoia_core::{Config, Context, NetworkPolicy};
use sequoia_net::KeyServer;
/* sequoia::Context. */
@@ -118,6 +118,19 @@ pub extern "system" fn sq_context_lib(ctx: Option<&Context>) -> *const c_char {
ctx.unwrap().lib().to_string_lossy().as_bytes().as_ptr() as *const c_char
}
+/// Returns the network policy.
+#[no_mangle]
+pub extern "system" fn sq_context_network_policy(ctx: Option<&Context>) -> uint8_t {
+ assert!(ctx.is_some());
+ match ctx.unwrap().network_policy() {
+ &NetworkPolicy::Offline => 0,
+ &NetworkPolicy::Anonymized => 1,
+ &NetworkPolicy::Encrypted => 2,
+ &NetworkPolicy::Insecure => 3,
+ }
+}
+
+
/* sequoia::Config. */
/// Finalizes the configuration and return a `Context`.
@@ -160,6 +173,20 @@ pub extern "system" fn sq_config_lib(cfg: Option<&mut Config>,
cfg.unwrap().set_lib(&lib.as_ref())
}
+/// Sets the network policy.
+#[no_mangle]
+pub extern "system" fn sq_config_network_policy(cfg: Option<&mut Config>,
+ policy: uint8_t) {
+ assert!(cfg.is_some());
+ cfg.unwrap().set_network_policy(match policy {
+ 0 => NetworkPolicy::Offline,
+ 1 => NetworkPolicy::Anonymized,
+ 2 => NetworkPolicy::Encrypted,
+ 3 => NetworkPolicy::Insecure,
+ n => panic!("Bad policy: {}", n),
+ });
+}
+
/* openpgp::types. */
/// Returns a KeyID with the given `id`.
diff --git a/ffi/src/sequoia.h b/ffi/src/sequoia.h
index c3b3db04..c19db967 100644
--- a/ffi/src/sequoia.h
+++ b/ffi/src/sequoia.h
@@ -25,6 +25,27 @@ struct sq_context;
struct sq_config;
/*/
+/// Network policy for Sequoia.
+///
+/// With this policy you can control how Sequoia accesses remote
+/// systems.
+/*/
+
+/* Do not contact remote systems. */
+#define SQ_NETWORK_POLICY_OFFLINE 0
+
+/* Only contact remote systems using anonymization techniques
+ * like TOR. */
+#define SQ_NETWORK_POLICY_ANONYMIZED 1
+
+/* Only contact remote systems using transports offering
+ * encryption and authentication like TLS. */
+#define SQ_NETWORK_POLICY_ENCRYPTED 2
+
+/* Contact remote systems even with insecure transports. */
+#define SQ_NETWORK_POLICY_INSECURE 3
+
+/*/
/// Creates a Context with reasonable defaults.
///
/// `domain` should uniquely identify your application, it is strongly
@@ -68,6 +89,11 @@ const char *sq_context_home(const struct sq_context *ctx);
/*/
const char *sq_context_lib(const struct sq_context *ctx);
+/*/
+/// Returns the network policy.
+/*/
+uint8_t sq_context_network_policy(const struct sq_context *ctx);
+
/* sequoia::Config. */
@@ -88,6 +114,12 @@ void sq_config_home(struct sq_config *cfg, const char *home);
/*/
void sq_config_lib(struct sq_config *cfg, const char *lib);
+/*/
+/// Sets the network policy.
+/*/
+void sq_config_network_policy(struct sq_config *cfg, uint8_t policy);
+
+
/* sequoia::openpgp::types. */
/*/
diff --git a/net/src/lib.rs b/net/src/lib.rs
index 36b822c1..b0e10a71 100644
--- a/net/src/lib.rs
+++ b/net/src/lib.rs
@@ -51,7 +51,7 @@ use std::convert::From;
use std::io::{Cursor, Read};
use std::io;
-use sequoia_core::Context;
+use sequoia_core::{Context, NetworkPolicy};
use openpgp::tpk::{self, TPK};
use openpgp::types::KeyId;
use openpgp::{Message, armor};
@@ -128,9 +128,14 @@ impl KeyServer {
}
/// Common code for the above functions.
- fn make(_ctx: &Context, core: Core, client: Box<AClient>, uri: Uri) -> Result<Self> {
- let uri = {
- let s = uri.scheme().ok_or(Error::MalformedUri)?;
+ fn make(ctx: &Context, core: Core, client: Box<AClient>, uri: Uri) -> Result<Self> {
+ let s = uri.scheme().ok_or(Error::MalformedUri)?;
+ match s {
+ "hkp" => ctx.network_policy().assert(NetworkPolicy::Insecure),
+ "hkps" => ctx.network_policy().assert(NetworkPolicy::Encrypted),
+ _ => unreachable!()
+ }?;
+ let uri =
format!("{}://{}:{}",
match s {"hkp" => "http", "hkps" => "https", _ => unreachable!()},
uri.host().ok_or(Error::MalformedUri)?,
@@ -138,8 +143,7 @@ impl KeyServer {
"hkp" => uri.port().or(Some(11371)),
"hkps" => uri.port().or(Some(443)),
_ => unreachable!(),
- }.unwrap())
- }.parse()?;
+ }.unwrap()).parse()?;
Ok(KeyServer{core: core, client: client, uri: uri})
}
@@ -248,6 +252,8 @@ pub enum Error {
ProtocolViolation,
/// There was an error parsing the key.
KeysError(tpk::Error),
+ /// A `sequoia_core::Error` occured.
+ CoreError(sequoia_core::Error),
/// Encountered an unexpected low-level http status.
HttpStatus(hyper::StatusCode),
/// An `io::Error` occured.
@@ -266,6 +272,12 @@ impl From<tpk::Error> for Error {
}
}
+impl From<sequoia_core::Error> for Error {
+ fn from(e: sequoia_core::Error) -> Self {
+ Error::CoreError(e)
+ }
+}
+
impl From<hyper::StatusCode> for Error {
fn from(status: hyper::StatusCode) -> Self {
Error::HttpStatus(status)