summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2021-01-15 09:35:04 +0100
committerJustus Winter <justus@sequoia-pgp.org>2021-01-15 11:34:49 +0100
commit59a59ac5bf9cc9be2698eb35376c3b58fd483252 (patch)
tree5eb5c8256c67b8397669c48fae905840c3302866 /net
parentde5c18230ddcad3928ae5c4bd2c1badbe9ec2e92 (diff)
net: Decouple from core.
- Move core::NetworkPolicy to net::Policy, update all code accordingly.
Diffstat (limited to 'net')
-rw-r--r--net/Cargo.toml1
-rw-r--r--net/src/lib.rs166
-rw-r--r--net/tests/hkp.rs18
3 files changed, 144 insertions, 41 deletions
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 => Policy::Offline,
+ 1 => Policy::Anonymized,
+ 2 => Policy::Encrypted,
+ 3 => Policy::Insecure,
+ n => panic!("Bad network policy: {}", n),
+ }
+ }
+}
+
/// For accessing keyservers using HKP.
pub struct KeyServer {
client: Box<dyn AClient>,
@@ -69,7 +136,7 @@ pub struct KeyServer {
impl KeyServer {
/// Returns a handle for the given URI.
- pub fn new(ctx: &Context, uri: &str) -> Result<Self> {
+ pub fn new(p: Policy, uri: &str) -> Result<Self> {
let uri: Url = uri.parse()
.or_else(|_| format!("hkps://{}", uri).parse())?;
@@ -82,13 +149,13 @@ impl KeyServer {
_ => return Err(Error::MalformedUri.into()),
};
- Self::make(ctx, client, uri)
+ Self::make(p, client, uri)
}
/// Returns a handle for the given URI.
///
/// `cert` is used to authenticate the server.
- pub fn with_cert(ctx: &Context, uri: &str, cert: Certificate)
+ pub fn with_cert(p: Policy, uri: &str, cert: Certificate)
-> Result<Self> {
let uri: Url = uri.parse()?;
@@ -103,23 +170,23 @@ impl KeyServer {
.build(HttpsConnector::from((http, tls.into()))))
};
- Self::make(ctx, client, uri)
+ Self::make(p, client, uri)
}
/// Returns a handle for keys.openpgp.org.
///
/// The server at `hkps://keys.openpgp.org` distributes updates
/// for OpenPGP certificates. It is a good default choice.
- pub fn keys_openpgp_org(ctx: &Context) -> Result<Self> {
- Self::new(ctx, "hkps://keys.openpgp.org")
+ pub fn keys_openpgp_org(p: Policy) -> Result<Self> {
+ Self::new(p, "hkps://keys.openpgp.org")
}
/// Common code for the above functions.
- fn make(ctx: &Context, client: Box<dyn AClient>, uri: Url) -> Result<Self> {
+ fn make(p: Policy, client: Box<dyn AClient>, uri: Url) -> Result<Self> {
let s = uri.scheme();
match s {
- "hkp" => ctx.network_policy().assert(NetworkPolicy::Insecure),
- "hkps" => ctx.network_policy().assert(NetworkPolicy::Encrypted),
+ "hkp" => p.assert(Policy::Insecure),
+ "hkps" => p.assert(Policy::Encrypted),
_ => return Err(Error::MalformedUri.into())
}?;
let uri =
@@ -301,6 +368,10 @@ pub type Result<T> = ::std::result::Result<T, anyhow::Error>;
#[derive(thiserror::Error, Debug)]
/// Errors returned from the network routines.
pub enum Error {
+ /// The network policy was violated by the given action.
+ #[error("Unmet network policy requirement: {0}")]
+ PolicyViolation(Policy),
+
/// A requested key was not found.
#[error("Key not found")]
NotFound,
@@ -346,22 +417,63 @@ pub enum Error {
mod tests {
use super::*;
+ fn ok(policy: Policy, required: Policy) {
+ assert!(policy.assert(required).is_ok());
+ }
+
+ fn fail(policy: Policy, required: Policy) {
+ assert!(matches!(
+ policy.assert(required)
+ .err().unwrap().downcast::<Error>().unwrap(),
+ Error::PolicyViolation(_)));
+ }
+
#[test]
- fn uris() {
- let ctx = Context::configure()
- .network_policy(sequoia_core::NetworkPolicy::Insecure)
- .build().unwrap();
+ fn offline() {
+ let p = Policy::Offline;
+ ok(p, Policy::Offline);
+ fail(p, Policy::Anonymized);
+ fail(p, Policy::Encrypted);
+ fail(p, Policy::Insecure);
+ }
- assert!(KeyServer::new(&ctx, "keys.openpgp.org").is_ok());
- assert!(KeyServer::new(&ctx, "hkp://keys.openpgp.org").is_ok());
- assert!(KeyServer::new(&ctx, "hkps://keys.openpgp.org").is_ok());
+ #[test]
+ fn anonymized() {
+ let p = Policy::Anonymized;
+ ok(p, Policy::Offline);
+ ok(p, Policy::Anonymized);
+ fail(p, Policy::Encrypted);
+ fail(p, Policy::Insecure);
+ }
+
+ #[test]
+ fn encrypted() {
+ let p = Policy::Encrypted;
+ ok(p, Policy::Offline);
+ ok(p, Policy::Anonymized);
+ ok(p, Policy::Encrypted);
+ fail(p, Policy::Insecure);
+ }
- let ctx = Context::configure()
- .network_policy(sequoia_core::NetworkPolicy::Encrypted)
- .build().unwrap();
+ #[test]
+ fn insecure() {
+ let p = Policy::Insecure;
+ ok(p, Policy::Offline);
+ ok(p, Policy::Anonymized);
+ ok(p, Policy::Encrypted);
+ ok(p, Policy::Insecure);
+ }
- assert!(KeyServer::new(&ctx, "keys.openpgp.org").is_ok());
- assert!(KeyServer::new(&ctx, "hkp://keys.openpgp.org").is_err());
- assert!(KeyServer::new(&ctx, "hkps://keys.openpgp.org").is_ok());
+ #[test]
+ fn uris() {
+ let p = Policy::Insecure;
+ assert!(KeyServer::new(p, "keys.openpgp.org").is_ok());
+ assert!(KeyServer::new(p, "hkp://keys.openpgp.org").is_ok());
+ assert!(KeyServer::new(p, "hkps://keys.openpgp.org").is_ok());
+
+ let p = Policy::Encrypted;
+ assert!(KeyServer::new(p, "keys.openpgp.org").is_ok());
+ assert!(KeyServer::new(p, "hkp://keys.openpgp.org").is_err());
+ assert!(KeyServer::new(p, "hkps://keys.openpgp.org").is_ok());
}
}
diff --git a/net/tests/hkp.rs b/net/tests/hkp.rs
index 8dafe9a6..f1984529 100644
--- a/net/tests/hkp.rs
+++ b/net/tests/hkp.rs
@@ -11,7 +11,7 @@ use sequoia_openpgp::KeyID;
use sequoia_openpgp::armor::Reader;
use sequoia_openpgp::Cert;
use sequoia_openpgp::parse::Parse;
-use sequoia_core::{Context, NetworkPolicy};
+use sequoia_net as net;
use sequoia_net::KeyServer;
const RESPONSE: &'static str = "-----BEGIN PGP PUBLIC KEY BLOCK-----
@@ -118,17 +118,14 @@ fn start_server() -> SocketAddr {
addr
}
+const P: net::Policy = net::Policy::Insecure;
+
#[tokio::test]
async fn get() -> anyhow::Result<()> {
- let ctx = Context::configure()
- .ephemeral()
- .network_policy(NetworkPolicy::Insecure)
- .build()?;
-
// Start server.
let addr = start_server();
- let mut keyserver = KeyServer::new(&ctx, &format!("hkp://{}", addr))?;
+ let mut keyserver = KeyServer::new(P, &format!("hkp://{}", addr))?;
let keyid: KeyID = ID.parse()?;
let key = keyserver.get(keyid).await?;
@@ -139,16 +136,11 @@ async fn get() -> anyhow::Result<()> {
#[tokio::test]
async fn send() -> anyhow::Result<()> {
- let ctx = Context::configure()
- .ephemeral()
- .network_policy(NetworkPolicy::Insecure)
- .build()?;
-
// Start server.
let addr = start_server();
eprintln!("{}", format!("hkp://{}", addr));
let mut keyserver =
- KeyServer::new(&ctx, &format!("hkp://{}", addr))?;
+ KeyServer::new(P, &format!("hkp://{}", addr))?;
let key = Cert::from_reader(Reader::new(Cursor::new(RESPONSE), None))?;
keyserver.send(&key).await?;