summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2020-12-09 13:35:23 +0100
committerJustus Winter <justus@sequoia-pgp.org>2020-12-09 13:40:28 +0100
commit172955fe39e7b800e06c63ac4ad9bc7d1ed84c56 (patch)
tree909f3c9783eb62591032d8003f71a620c8e5c12e
parentd59776d18a34561fa846ac2638219aebd7e610c9 (diff)
net: Implement searching for email addresses via hkp.
-rw-r--r--net/src/lib.rs60
1 files changed, 57 insertions, 3 deletions
diff --git a/net/src/lib.rs b/net/src/lib.rs
index 27e94253..fa5b1659 100644
--- a/net/src/lib.rs
+++ b/net/src/lib.rs
@@ -39,9 +39,15 @@ use std::convert::From;
use std::io::Cursor;
use url::Url;
-use sequoia_openpgp::Cert;
-use sequoia_openpgp::parse::Parse;
-use sequoia_openpgp::{KeyHandle, armor, serialize::Serialize};
+use sequoia_openpgp as openpgp;
+use openpgp::{
+ armor,
+ cert::{Cert, CertParser},
+ KeyHandle,
+ packet::UserID,
+ parse::Parse,
+ serialize::Serialize,
+};
use sequoia_core::{Context, NetworkPolicy};
pub mod wkd;
@@ -180,6 +186,54 @@ impl KeyServer {
}
}
+ /// Retrieves certificates containing the given `UserID`.
+ ///
+ /// If the given [`UserID`] does not follow the de facto
+ /// conventions for userids, or it does not contain a email
+ /// address, an error is returned.
+ ///
+ /// [`UserID`]: https://docs.sequoia-pgp.org/sequoia_openpgp/packet/struct.UserID.html
+ ///
+ /// Any certificates returned by the server that do not contain
+ /// the email address queried for are silently discarded.
+ ///
+ /// # Warning
+ ///
+ /// Returned certificates must be mistrusted, and be carefully
+ /// interpreted under a policy and trust model.
+ pub async fn search<U: Into<UserID>>(&mut self, userid: U)
+ -> Result<Vec<Cert>>
+ {
+ let userid = userid.into();
+ let email = userid.email().and_then(|addr| addr.ok_or(
+ openpgp::Error::InvalidArgument(
+ "UserID does not contain an email address".into()).into()))?;
+ let uri = self.uri.join(
+ &format!("pks/lookup?op=get&options=mr&search={}", email))?;
+
+ let res = self.client.do_get(uri).await?;
+ match res.status() {
+ StatusCode::OK => {
+ let body = hyper::body::to_bytes(res.into_body()).await?;
+ let mut certs = Vec::new();
+ for certo in CertParser::from_bytes(&body)? {
+ let cert = certo?;
+ if cert.userids().any(|uid| {
+ uid.email().ok()
+ .and_then(|addro| addro)
+ .map(|addr| addr == email)
+ .unwrap_or(false)
+ }) {
+ certs.push(cert);
+ }
+ }
+ Ok(certs)
+ },
+ StatusCode::NOT_FOUND => Err(Error::NotFound.into()),
+ n => Err(Error::HttpStatus(n).into()),
+ }
+ }
+
/// Sends the given key to the server.
pub async fn send(&mut self, key: &Cert) -> Result<()> {
use sequoia_openpgp::armor::{Writer, Kind};