Skip to content

Commit

Permalink
impl using rpgp
Browse files Browse the repository at this point in the history
remove needless return
clippy complains about it

try implementing via rpgp
BUG: L148, somehow the fingerprint given by the key is not proper utf8

fix conversion bug

add note regarding bug
pgp::composed::signed_key::parse::from_armor_many seems to yield only one key when multiple are present
  • Loading branch information
fairingrey committed Jan 14, 2022
1 parent 38e33d7 commit 72f33df
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 4 deletions.
17 changes: 14 additions & 3 deletions did-webkey/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,25 @@ ssi = { version = "0.3", path = "../", features = [
], default-features = false }
async-trait = "0.1"
reqwest = { version = "0.11", features = ["json"] }
hex = "0.4"
http = "0.2"
sequoia-openpgp = { version = "1.7", features = [
"compression-deflate",
], default-features = false }
serde_json = "1.0"
serde = { version = "1.0", features = ["derive"] }
sshkeys = "0.3"

[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
sequoia-openpgp = { version = "1.7", features = [
"compression-deflate",
], default-features = false, optional = true }
# HACK: temp, point to crates once pgp publishes a version that doesn't require zeroize=1.3.0
pgp = { git = "https://github.com/rpgp/rpgp", rev = "21081b6aaaaa5750ab937cfef30bae879a740d23", optional = true }

[target.'cfg(target_arch = "wasm32")'.dependencies]
# HACK: same thing as above
pgp = { git = "https://github.com/rpgp/rpgp", rev = "21081b6aaaaa5750ab937cfef30bae879a740d23", features = [
"wasm",
] }

[target.'cfg(target_os = "android")'.dependencies.reqwest]
version = "0.11"
features = ["json", "native-tls-vendored"]
Expand Down
93 changes: 92 additions & 1 deletion did-webkey/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,27 @@ use core::str::FromStr;
use async_trait::async_trait;
use serde::{Deserialize, Serialize};

#[cfg(all(
not(target_arch = "wasm32"),
feature = "sequoia-openpgp",
not(feature = "pgp")
))]
use openpgp::{
cert::prelude::*,
parse::{PacketParser, Parse},
serialize::SerializeInto,
};
#[cfg(any(target_arch = "wasm32", feature = "pgp"))]
use pgp::{
composed::{PublicOrSecret, SignedPublicKey},
errors::Error as PgpError,
types::KeyTrait,
};
#[cfg(all(
not(target_arch = "wasm32"),
feature = "sequoia-openpgp",
not(feature = "pgp")
))]
use sequoia_openpgp as openpgp;
use sshkeys::PublicKeyKind;
use ssi::did::{DIDMethod, Document, VerificationMethod, VerificationMethodMap, DIDURL};
Expand Down Expand Up @@ -44,6 +60,11 @@ impl FromStr for DIDWebKeyType {
}
}

#[cfg(all(
not(target_arch = "wasm32"),
feature = "sequoia-openpgp",
not(feature = "pgp")
))]
fn parse_pubkeys_gpg(
did: &str,
bytes: Vec<u8>,
Expand All @@ -68,6 +89,11 @@ fn parse_pubkeys_gpg(
Ok((vm_maps, did_urls))
}

#[cfg(all(
not(target_arch = "wasm32"),
feature = "sequoia-openpgp",
not(feature = "pgp")
))]
fn gpg_pk_to_vm(did: &str, cert: Cert) -> Result<(VerificationMethodMap, DIDURL), String> {
let vm_url = DIDURL {
did: did.to_string(),
Expand All @@ -92,6 +118,71 @@ fn gpg_pk_to_vm(did: &str, cert: Cert) -> Result<(VerificationMethodMap, DIDURL)
Ok((vm_map, vm_url))
}

#[cfg(any(target_arch = "wasm32", feature = "pgp"))]
fn parse_pubkeys_gpg(
did: &str,
bytes: Vec<u8>,
) -> Result<(Vec<VerificationMethodMap>, Vec<DIDURL>), String> {
use std::io::Cursor;

let mut did_urls = Vec::new();
let mut vm_maps = Vec::new();

let c = Cursor::new(bytes);
// BUG: This seems to yield only one key.
let keys = pgp::composed::signed_key::parse::from_armor_many(c)
.map_err(|e| format!("Unable to parse GPG keyring: {}", e))?
.0
.collect::<Result<Vec<PublicOrSecret>, PgpError>>()
.map_err(|e| format!("Unable to parse GPG keyring: {}", e))?;

for key in keys {
// ignore if secret key (which shouldn't happen)
let key = if let PublicOrSecret::Public(inner) = key {
inner
} else {
continue;
};
let (vm_map, did_url) = gpg_pk_to_vm(did, key).map_err(|e| {
format!(
"Unable to convert GPG public key to verification method: {}",
e
)
})?;
vm_maps.push(vm_map);
did_urls.push(did_url);
}

Ok((vm_maps, did_urls))
}

#[cfg(any(target_arch = "wasm32", feature = "pgp"))]
fn gpg_pk_to_vm(
did: &str,
key: SignedPublicKey,
) -> Result<(VerificationMethodMap, DIDURL), String> {
let fingerprint: String = hex::encode_upper(key.fingerprint());

let vm_url = DIDURL {
did: did.to_string(),
fragment: Some(fingerprint),
..Default::default()
};

let armored_pgp = key
.to_armored_string(None)
.map_err(|e| format!("Failed to re-serialize cert: {}", e))?;

let vm_map = VerificationMethodMap {
id: vm_url.to_string(),
type_: "PgpVerificationKey2021".to_string(),
public_key_pgp: Some(armored_pgp),
controller: did.to_string(),
..Default::default()
};
Ok((vm_map, vm_url))
}

fn pk_to_vm_ed25519(
did: &str,
pk: sshkeys::Ed25519PublicKey,
Expand Down Expand Up @@ -420,7 +511,7 @@ mod tests {
let (mut parts, body) = Response::<Body>::default().into_parts();
parts.status = hyper::StatusCode::NOT_FOUND;
let response = Response::from_parts(parts, body);
return Ok::<_, hyper::Error>(response);
Ok::<_, hyper::Error>(response)
}))
});
let server = Server::try_bind(&addr)?.serve(make_svc);
Expand Down

0 comments on commit 72f33df

Please sign in to comment.