Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement parsing GPG keys #373

Merged
merged 11 commits into from
Feb 24, 2022
Merged

Conversation

fairingrey
Copy link
Contributor

Addresses #204

@fairingrey fairingrey changed the title Impl gpg keytype Implement parsing GPG keys Jan 8, 2022
@fairingrey fairingrey marked this pull request as ready for review January 11, 2022 20:00
@fairingrey
Copy link
Contributor Author

fairingrey commented Jan 11, 2022

Will also note I should probably use some other dummy test data for the GPG keyring instead of my own from github.

EDIT: Done

@fairingrey fairingrey force-pushed the impl-gpg-keytype branch 2 times, most recently from 7e3289d to 62e45a4 Compare January 11, 2022 20:36
@wyc wyc requested a review from clehner January 11, 2022 21:33
@clehner
Copy link
Contributor

clehner commented Jan 11, 2022

Hi @fairingrey,
This looks very cool and well-implemented. I tried it with my key (rsa4096) and it resolves successfully and decodes the primary key. Nice work!

I am wondering how signatures will be made. I am seeing somewhat of a mismatch between what is implemented here and the referenced PgpVerificationKey2021 draft specification.

This PR is parsing the public key into a verification method object containing a JWK - similar to what did:webkey:ssh is doing - but using PgpVerificationKey2021 as the verification method type. But in the specification, PgpVerificationKey2021 passes through the ASCII-armored PGP public key in the publicKeyPgp property of the verification method, and publicKeyJwk is not mentioned.

In the webkey:ssh implementation, converting a SSH public key to a verification method object with JWK works because SSH Agent can be used to request a signature over an arbitrary payload. Signing over an arbitrary payload allows using existing signature formats. Using existing signature formats is desirable for interoperability. PgpVerificationKey2021 represents a new signature format, but it has a specification (albeit not yet in the CCG or a working group apparently). I assumed that GPG Agent would not sign arbitrary payloads and that therefore this new suite would be necessary.

Looking into GPG Agent now, I see it can sign a hash from particular algorithms, but not an arbitrary payload:
https://www.gnupg.org/documentation/manuals/gnupg/Agent-PKSIGN.html#Agent-PKSIGN

Many of the existing signature algorithms and proof types are based on signing a SHA-256 hash, fortunately; but some are not, in particular the Ed25519 ones.

I see some general possible ways to proceed:

  • Option 1. Try to align with the PgpVerificationKey2021 specification. Instead of parsing the PGP public key data, pass it through in the publicKeyPgp property.
  • Option 2. Continue with trying to use existing key/signature types. Change the verification method type from PgpVerificationKey2021 to JsonWebSignature2020 and/or to the key/algorithm-specific proof types like in webkey:ssh. This would enable using the existing signature/proof types - except a new one might be needed for Ed25519.
  • Option 3. Both of the above. Have the PgpVerificationKey2021 verification method alongside the other more common verification method types.

With SSH, translating the public keys is fairly straightforward (except for certificates, DSS, and the comment field, all of which are dropped in the current implementation), but GPG public keys and signatures are significantly more complex.

Option 1 I think would be simpler, as there would be a more well-defined interface between the signature suite and the OpenPGP implementation, i.e. the ASCII-armored public key and signature values. If using Option 2, it might be good to implement more of OpenPGP here, i.e. handling subkeys, expirations/revocations and key use/type flags. (e.g. currently the primary key is returned only, but the primary key might be expired, or it might be flagged as for certification purpose only rather than for signing; a user might want to sign with a subkey, etc.) To fully translate the PGP public key data into verification methods, I wonder if it would make sense to verify signature packets and apply their updates.

@fairingrey
Copy link
Contributor Author

fairingrey commented Jan 11, 2022

@clehner Thanks for your review! Yes I had a bit of trouble understanding the spec in https://or13.github.io/lds-pgp2021/ so I thought I'd start by at least trying to understand what the ssh implementation does and just copy that for the time being. I was worried there would be a few discrepancies and I'm glad they were pointed out.

I guess for right now working on Option 1 would be ideal, but I do feel as if I need some more guidance on how exactly it would look; so disregard parsing it into a JWK, and pass the ASCII-armored block as publicKeyPgp in the DID itself, right? (as in https://or13.github.io/lds-pgp2021/#example-example-did-document) Some of this stuff goes a bit over my head.

@wyc
Copy link
Contributor

wyc commented Jan 12, 2022

Option 1 sounds great to support, let's aim for Option 3 too! Eventually SSI should have clean separation across VMs as well.

@clehner
Copy link
Contributor

clehner commented Jan 12, 2022

@fairingrey

disregard parsing it into a JWK, and pass the ASCII-armored block as publicKeyPgp in the DID itself, right? (as in https://or13.github.io/lds-pgp2021/#example-example-did-document)

Yes, in the verification method object with type PgpVerificationKey2021. The id fragment should probably also be changed, e.g. to the PGP key id. (So the key data would still need to be parsed to get the primary key id.)

The existing verification method objects using publicKeyJwk (for Option 2/3) could have their type changed to a type that works with publicKeyJwk, i.e. either JsonWebKey2020 or the various types used in webkey:ssh. Using JWK thumbprint for those objects' id/fragment is good (Using PGP key id instead would also be good - but then it would probably need to be namespaced to avoid conflicting with the ids for PgpVerificationKey2021 in Option 1/3)

@fairingrey fairingrey marked this pull request as draft January 12, 2022 19:30
@fairingrey
Copy link
Contributor Author

@clehner I've pushed a few new commits with the changes requested (after a lot of digging through the openpgp library I was using, figured I wanted the high-level Certs). Does this better fit the spec? I've also included one note regarding the DID fragment I'm using, as it's not the keyid but the fingerprint: https://github.com/spruceid/ssi/pull/373/files#diff-7e39467d150fd9f27bc71d85ac25bad1a2f0bd0b510b2c9116a14b649fb85ad5R74-R75

Would appreciate another look, thanks again!

@fairingrey fairingrey marked this pull request as ready for review January 13, 2022 21:21
@wyc
Copy link
Contributor

wyc commented Jan 13, 2022

@fairingrey the build seems to be breaking, could you investigate how to fix this? We may need to add more dependencies to build your parts.

@fairingrey
Copy link
Contributor Author

fairingrey commented Jan 13, 2022

@fairingrey the build seems to be breaking, could you investigate how to fix this? We may need to add more dependencies to build your parts.

I believe the build machine requires nettle as a dependency because of sequoia, I'll try looking into how to pull that in

EDIT: May also want to edit the relevant Cargo.toml to allow certain features https://gitlab.com/sequoia-pgp/sequoia#note

@clehner
Copy link
Contributor

clehner commented Jan 13, 2022

@fairingrey yes, looks great!

Looks like Fingerprint is right rather than Key ID.


The bzip2/bzip2-sys transitive dependency causes a build failure in DIDKit WASM. I was going to suggest making sequoia-openpgp an optional, or non-WASM-only, dependency of the did-webkey crate. But it looks like Sequoia can use flate2 instead of bzip2, and we already have flate2 in the dependency tree so I think that would make sense to use:
https://gitlab.com/sequoia-pgp/sequoia#compression

The nettle-dev package, if that is what is needed, could be installed in the CI script and mentioned in the Dependencies section of the readme. But maybe it would be better to use the Sequoia's crypto-cng backend?


The Document should have some additional context set to define the "publicKeyPgp" and "PgpVerificationKey2021" terms, e.g. using https://w3id.org/pgp/v1. But this could be done separately.


Dependencies added
├── sequoia-openpgp v1.7.0
│   ├── anyhow v1.0.52
│   ├── backtrace v0.3.63 (*)
│   ├── base64 v0.13.0
│   ├── buffered-reader v1.1.2
│   │   ├── bzip2 v0.4.3
│   │   │   ├── bzip2-sys v0.1.11+1.0.8
│   │   │   │   └── libc v0.2.112
│   │   │   └── libc v0.2.112
│   │   ├── flate2 v1.0.22 (*)
│   │   └── libc v0.2.112
│   ├── bzip2 v0.4.3 (*)
│   ├── dyn-clone v1.0.4
│   ├── flate2 v1.0.22 (*)
│   ├── idna v0.2.3 (*)
│   ├── lalrpop-util v0.19.6
│   │   └── regex v1.5.4
│   │       ├── aho-corasick v0.7.18
│   │       │   └── memchr v2.4.1
│   │       ├── memchr v2.4.1
│   │       └── regex-syntax v0.6.25
│   ├── lazy_static v1.4.0
│   ├── libc v0.2.112
│   ├── memsec v0.6.0
│   ├── nettle v7.0.3
│   │   ├── getrandom v0.2.3 (*)
│   │   ├── libc v0.2.112
│   │   ├── nettle-sys v2.0.8
│   │   └── thiserror v1.0.30
│   │       └── thiserror-impl v1.0.30 (proc-macro)
│   │           ├── proc-macro2 v1.0.36 (*)
│   │           ├── quote v1.0.14 (*)
│   │           └── syn v1.0.85 (*)
│   ├── regex v1.5.4 (*)
│   ├── regex-syntax v0.6.25
│   ├── sha1collisiondetection v0.2.5
│   │   ├── digest v0.9.0 (*)
│   │   └── generic-array v0.14.5 (*)
│   ├── thiserror v1.0.30 (*)
│   └── xxhash-rust v0.8.2
Build failure with WASM
   Compiling bzip2-sys v0.1.11+1.0.8
   Compiling ring v0.16.20
   Compiling indexmap v1.7.0
   Compiling aho-corasick v0.7.18
   Compiling nom v5.1.2
   Compiling dirs-sys-next v0.1.2
The following warnings were emitted during compilation:

warning: In file included from bzip2-1.0.8/blocksort.c:22:
warning: bzip2-1.0.8/bzlib_private.h:25:10: fatal error: 'stdlib.h' file not found
warning: #include <stdlib.h>
warning:          ^~~~~~~~~~
warning: 1 error generated.

error: failed to run custom build command for `bzip2-sys v0.1.11+1.0.8`

Caused by:
  process didn't exit successfully: `/home/cel/src/didkit/target/release/build/bzip2-sys-bf09ffff921cefdb/build-script-build` (exit status: 1)
  --- stdout
  cargo:rerun-if-env-changed=BZIP2_NO_PKG_CONFIG
  cargo:rerun-if-env-changed=PKG_CONFIG_ALLOW_CROSS_wasm32-unknown-unknown
  cargo:rerun-if-env-changed=PKG_CONFIG_ALLOW_CROSS_wasm32_unknown_unknown
  cargo:rerun-if-env-changed=TARGET_PKG_CONFIG_ALLOW_CROSS
  cargo:rerun-if-env-changed=PKG_CONFIG_ALLOW_CROSS
  cargo:rerun-if-env-changed=PKG_CONFIG_wasm32-unknown-unknown
  cargo:rerun-if-env-changed=PKG_CONFIG_wasm32_unknown_unknown
  cargo:rerun-if-env-changed=TARGET_PKG_CONFIG
  cargo:rerun-if-env-changed=PKG_CONFIG
  cargo:rerun-if-env-changed=PKG_CONFIG_SYSROOT_DIR_wasm32-unknown-unknown
  cargo:rerun-if-env-changed=PKG_CONFIG_SYSROOT_DIR_wasm32_unknown_unknown
  cargo:rerun-if-env-changed=TARGET_PKG_CONFIG_SYSROOT_DIR
  cargo:rerun-if-env-changed=PKG_CONFIG_SYSROOT_DIR
  TARGET = Some("wasm32-unknown-unknown")
  OPT_LEVEL = Some("3")
  HOST = Some("x86_64-unknown-linux-gnu")
  CC_wasm32-unknown-unknown = None
  CC_wasm32_unknown_unknown = None
  TARGET_CC = None
  CC = None
  CFLAGS_wasm32-unknown-unknown = None
  CFLAGS_wasm32_unknown_unknown = None
  TARGET_CFLAGS = None
  CFLAGS = None
  CRATE_CC_NO_DEFAULTS = None
  DEBUG = Some("false")
  running: "clang" "-O3" "-ffunction-sections" "-fdata-sections" "-fPIC" "--target=wasm32-unknown-unknown" "-I" "bzip2-1.0.8" "-D_FILE_OFFSET_BITS=64" "-DBZ_NO_STDIO" "-o" "/home/cel/src/didkit/target/wasm32-unknown-unknown/release/build/bzip2-sys-7f9683b0dad6d32c/out/lib/bzip2-1.0.8/blocksort.o" "-c" "bzip2-1.0.8/blocksort.c"
  cargo:warning=In file included from bzip2-1.0.8/blocksort.c:22:
  cargo:warning=bzip2-1.0.8/bzlib_private.h:25:10: fatal error: 'stdlib.h' file not found
  cargo:warning=#include <stdlib.h>
  cargo:warning=         ^~~~~~~~~~
  cargo:warning=1 error generated.
  exit status: 1

  --- stderr


  error occurred: Command "clang" "-O3" "-ffunction-sections" "-fdata-sections" "-fPIC" "--target=wasm32-unknown-unknown" "-I" "bzip2-1.0.8" "-D_FILE_OFFSET_BITS=64" "-DBZ_NO_STDIO" "-o" "/home/cel/src/didkit/target/wasm32-unknown-unknown/release/build/bzip2-sys-7f9683b0dad6d32c/out/lib/bzip2-1.0.8/blocksort.o" "-c" "bzip2-1.0.8/blocksort.c" with args "clang" did not execute successfully (status code exit status: 1).


warning: build failed, waiting for other jobs to finish...
error: build failed
Error: Compiling your crate to WebAssembly failed
Caused by: failed to execute `cargo build`: exited with exit code: 101
  full command: "cargo" "build" "--lib" "--release" "--target" "wasm32-unknown-unknown"

Cargo.toml Outdated Show resolved Hide resolved
required for sequoia pgp dependency
allows users to pick between which crypto lib (cng or nettle)
uses flate compression by default
@fairingrey
Copy link
Contributor Author

I'll squash my commits once I'm sure the CI finishes the job.

@fairingrey
Copy link
Contributor Author

Huh. So nettle won't build for WASM, which I guess should be specified under a feature flag. It might be worth using the Rust PGP implementation to support this (https://github.com/rpgp/rpgp)

@fairingrey
Copy link
Contributor Author

fairingrey commented Jan 14, 2022

pgp::composed::signed_key::parse::from_armor_many seems to only read one key despite three being present in the test keyring: https://github.com/spruceid/ssi/pull/373/files#diff-7e39467d150fd9f27bc71d85ac25bad1a2f0bd0b510b2c9116a14b649fb85ad5R119-R120

It might be related to rpgp/rpgp#131

@fairingrey
Copy link
Contributor Author

Alright I think this is ready for one more review @clehner. Some things of note:

  • As mentioned above there seems to be a bug with the rpgp library where it only yields one public key out of three in a keyring. Not sure how to handle this, I'd like some input
  • rpgp has not yet published to crates a version that does not have zeroize=1.3.0 as a pinned dependency, so I'm currently using a git dependency.
  • Cargo resolver v2 is necessary to avoid sequoia-openpgp being built on the wasm32 target architecture (as there's currently no way in Rust to enable/disable certain features for a given target; it's a workaround). I wanted to make particular note that this significantly increases the build times for the other workspace members, but I think work going into reducing these dependencies being rebuilt can go in a different PR.

@fairingrey
Copy link
Contributor Author

fairingrey commented Jan 17, 2022

Also just as an aside to the rest of the code in this crate, I find the reliance on String error types a bit cumbersome -- is it possible we could just use anyhow or something similar to handle errors?

add note regarding bug
pgp::composed::signed_key::parse::from_armor_many seems to yield only one key when multiple are present

use feature resolver v2 (necessary since nettle will not compile on wasm32)
https://doc.rust-lang.org/cargo/reference/features.html#feature-resolver-version-2

add notes on pgp specific dependencies
@clehner
Copy link
Contributor

clehner commented Jan 20, 2022

As mentioned above there seems to be a bug with the rpgp library where it only yields one public key out of three in a keyring. Not sure how to handle this, I'd like some input

Two options:

  1. Use one verification method for the keyring data. It's id should then be something well-known to the DID document, like "#key" or "...#publicKeyPgp", rather than a key id derived from the keyring contents. The key data might then not need to be parsed at all to produce the DID document. Or...
  2. Stick to using multiple verification methods, one for each public key. When this isn't possible, DID resolution can fail with an error. On WASM we might need to disable webkey:gpg functionality, to avoid adding the sequoia-openpgp dependency (unless using Crago resolver v2 as you said) or until the multiple keys can be accessed using rPGP (to avoid providing an inconsistent implementation).

I like the multiple verification methods approach, as it makes it more obvious what keys the DID document contains by inspection. But if it's not practical, I'm not sure it adds much other benefits. It would be useful to know if OpenPGP implementations (i.e. including rPGP) commonly support verifying signatures against these multiple-public-key files (I assume they do. But we might not find out until later).

Here's a new issue on the PGP Vocabulary v1 asking about use of multiple public keys in a publicKeyPgp field: OR13/lds-pgp2021#3

rpgp has not yet published to crates a version that does not have zeroize=1.3.0 as a pinned dependency, so I'm currently using a git dependency.

OK. Maybe it could work to allow the old zeroize dependency, like how we have rand_old in Cargo.toml currently? But we can deal with a git dependency for now I think.

Cargo resolver v2 is necessary to avoid sequoia-openpgp being built on the wasm32 target architecture (as there's currently no way in Rust to enable/disable certain features for a given target; it's a workaround). I wanted to make particular note that this significantly increases the build times for the other workspace members, but I think work going into reducing these dependencies being rebuilt can go in a different PR.

OK, thanks.

Also just as an aside to the rest of the code in this crate, I find the reliance on String error types a bit cumbersome -- is it possible we could just use anyhow or something similar to handle errors?

Using anyhow more would be good I think. The use of String error types, and the singleton Error type, is probably not ideal.

Errors have to be returned as strings in the following two APIs:

  1. DID Resolution Metadata and DID URL Dereferencing Metadata - error property

    ssi/src/did_resolve.rs

    Lines 68 to 70 in 5ebd115

    pub struct ResolutionMetadata {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub error: Option<String>,

    ssi/src/did_resolve.rs

    Lines 108 to 110 in 5ebd115

    pub struct DereferencingMetadata {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub error: Option<String>,

    The value is supposed to be a single keyword, like an enum, where specific values are registered in DID Specification Registries. Sometimes in ssi we are instead putting a whole error message in that field rather than just the keyword. That could perhaps be changed to pass the error message in a separate field like errorMessage or errorStack (keeping in mind that the resolution/dereferencing endpoint might be called by remote third-parties, so should not reveal sensitive information).
  2. VC API Verification Result - errors array

    ssi/src/vc.rs

    Lines 505 to 512 in 5ebd115

    pub struct VerificationResult {
    /// The checks performed
    pub checks: Vec<Check>,
    /// Warnings
    pub warnings: Vec<String>,
    /// Errors
    pub errors: Vec<String>,
    }

    The structure of the error strings here are not specified, so we just do whatever. (The "checks" field is enum-like, but it's not clear to me that that will be the case for "warnings" and "errors" fields.) Serializing a StdError including backtrace data (source error chain) might be good. ssi::error::Error doesn't implement std::error::Error currently, but probably should (unless removing it entirely).

also include test output for both pgp libs
@fairingrey
Copy link
Contributor Author

I like the multiple verification methods approach, as it makes it more obvious what keys the DID document contains by inspection. But if it's not practical, I'm not sure it adds much other benefits. It would be useful to know if OpenPGP implementations (i.e. including rPGP) commonly support verifying signatures against these multiple-public-key files (I assume they do. But we might not find out until later).

I also prefer the multiple verification methods approach as I prefer more explicitness over implicitness and the format is generally more readable to me. Both sequoia and rpgp support verifying messages/signatures against pgp pubkeys, but I find sequoia much easier to work with.

OK. Maybe it could work to allow the old zeroize dependency, like how we have rand_old in Cargo.toml currently? But we can deal with a git dependency for now I think.

Unfortunately not, doing so would require downgrading the bbs crate to a suitable version and reworking code to older dependencies is an ugly can of worms. But hopefully a newer release will remedy it.

I guess for now I can rework the error types. I'll leave in the pgp implementation for now (in the hopes it'll be fixed later on), but if it shouldn't be used that's also fine as well.

include anyhow; upgrade rest of deps
did-webkey/src/lib.rs Outdated Show resolved Hide resolved
@clehner
Copy link
Contributor

clehner commented Feb 2, 2022

With these changes, didkit-wasm fails to build, because the ring and ed25519-dalek features are enabled in ssi, which is a conflict in the jwk module. I'm guessing this is because of Cargo resolver v2, but haven't figured out if it needs to be addressed in didkit or in ssi (or both).

@clehner
Copy link
Contributor

clehner commented Feb 16, 2022

Looking at this again...
The build failure in didkit-wasm was not because of cargo resolver v2 but because of depending on the the ring feature of ssi in a non-optional way. Suggest to depend on ring in a default but optional way:

--- a/did-webkey/Cargo.toml
+++ b/did-webkey/Cargo.toml
@@ -12,17 +12,13 @@ homepage = "https://github.com/spruceid/ssi/tree/main/did-webkey/"
 documentation = "https://docs.rs/did-webkey/"
 
 [features]
-default = ["sequoia-openpgp/crypto-nettle"]
+default = ["ssi/ring", "sequoia-openpgp/crypto-nettle"]
 crypto-cng = ["sequoia-openpgp/crypto-cng"]
 crypto-nettle = ["sequoia-openpgp/crypto-nettle"]
 p256 = ["ssi/p256"]
 
 [dependencies]
-ssi = { version = "0.3", path = "../", features = [
-    "rand",
-    "ring",
-    "p256",
-], default-features = false }
+ssi = { version = "0.3", path = "../", default-features = false, features = ["secp256r1"] }
 anyhow = "1.0.52"
 async-trait = "0.1.52"
 reqwest = { version = "0.11.9", features = ["json"] }

I'll leave in the pgp implementation for now (in the hopes it'll be fixed later on), but if it shouldn't be used that's also fine as well.

Makes sense... But I'm confused by the wasm32 targeting. I'm not sure what are the advantages of using rpgp. sequoia-openpgp supports WASM with the crypto-rust feature (with allow-experimental-crypto and allow-variable-time-crypto): https://gitlab.com/sequoia-pgp/sequoia/-/tree/main/openpgp#compiling-to-wasm - I was able to compile didkit-wasm using that. It looks like it uses some of the same crypto libraries as rpgp uses, i.e. ed25519-dalek and rsa (which ssi also uses in the non-ring feature set). Really I would think crypto libraries should not be needed here anyway: the webkey:gpg resolver as implemented here parses and splits the keyring file into multiple keyring files and create verification method objects for them, but does not appear to need to execute any cryptographic functions; the validity of the keyring could be checked, but that must be done when verifying a signature anyway. The actual signing and verifying (and/or encrypting/decrypting and key exchange which ssi doesn't do yet) would be done elsewhere in ssi. There is a library for parsing only, here: https://github.com/kpcyrd/sloppy-rfc4880 - it appears to support multiple PublicKey items in the keyring like in our example (Edit: but it does not reserialize/armor)

Copy link
Contributor

@clehner clehner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Attempting to address didkit-wasm in #390

@fairingrey
Copy link
Contributor Author

fairingrey commented Feb 16, 2022

Looking at this again... The build failure in didkit-wasm was not because of cargo resolver v2 but because of depending on the the ring feature of ssi in a non-optional way.

Alright, I can follow up with this diff.

Makes sense... But I'm confused by the wasm32 targeting. I'm not sure what are the advantages of using rpgp. sequoia-openpgp supports WASM with the crypto-rust feature (with allow-experimental-crypto and allow-variable-time-crypto): https://gitlab.com/sequoia-pgp/sequoia/-/tree/main/openpgp#compiling-to-wasm - I was able to compile didkit-wasm using that. It looks like it uses some of the same crypto libraries as rpgp uses, i.e. ed25519-dalek and rsa (which ssi also uses in the non-ring feature set). Really I would think crypto libraries should not be needed here anyway: the webkey:gpg resolver as implemented here parses and splits the keyring file into multiple keyring files and create verification method objects for them, but does not appear to need to execute any cryptographic functions; the validity of the keyring could be checked, but that must be done when verifying a signature anyway. The actual signing and verifying (and/or encrypting/decrypting and key exchange which ssi doesn't do yet) would be done elsewhere in ssi. There is a library for parsing only, here: https://github.com/kpcyrd/sloppy-rfc4880 - it appears to support multiple PublicKey items in the keyring like in our example (Edit: but it does not reserialize/armor)

These are really good points. I hadn't caught on that sequoia-openpgp compiles to WASM so I opted to use rpgp for it instead.

The usage of crypto libraries was due in part to a batteries-enabled approach to this issue as I assumed in the future didkit could also be responsible for verifying webkey:gpg keys, but if only parsing is needed then certainly we could go with that approach (and thus reduce the footprint of using such a full-featured pgp library).

If we're going to stick with sequoia-openpgp (which is what I think is the best solution for now) then I'll remove the rpgp implementations and adjust the manifest to allow WASM compilation with sequoia as you've mentioned.

@fairingrey
Copy link
Contributor Author

You may have to check back around with me on how to let sequoia-openpgp compile on wasm32-unknown-unknown, I'm having a bit of trouble figuring out how to specify to the manifest to avoid enabling both crypto backends when I don't want them.

@clehner
Copy link
Contributor

clehner commented Feb 16, 2022

I think using just the crypto-rust backend for sequoia-openpgp in this DID resolver would be okay for both WASM and non-WASM.
Here is one way to do it: 311183f (Not every change there is necessary, it's just one way to make things work.)
Using the other backends or libraries could be revisited if/when adding PGP signing and verifying in ssi.

If this can work without changes in didkit, cool; otherwise, a change like this can be made: spruceid/didkit@b293fe0

If you want to test building didkit-wasm:

  • Clone didkit alongside ssi
  • Install wasm-pack
  • rustup target add wasm32-unknown-unknown
  • In didkit/lib/web, run wasm-pack build --out-dir pkg --target web

@clehner
Copy link
Contributor

clehner commented Feb 23, 2022

I'm having a bit of trouble figuring out how to specify to the manifest to avoid enabling both crypto backends when I don't want them.

I think I am reproducing this; it seems that the architecture-conditional dependency features (target_arch = "wasm32" ...) are not working, both the wasm and non-wasm feature sets are being applied in either case. This issue would seem to apply, but is closed: rust-lang/cargo#2524; resolver=2 is supposed to fix it (rust-lang/cargo#7914 (comment)) but doesn't seem to be doing so. Without architecture detection in the dependencies, it seems we must default to a set of features that works with WASM (Or add a feature to use in the WASM compilation check in CI and in didkit-wasm). sequoia-openpgp/crypto-rust appears to be the only way to do that here. I've updated #390 to rebase onto this PR (#373) and to use just sequoia-openpgp/crypto-rust.

@clehner clehner merged commit 2579d4d into spruceid:main Feb 24, 2022
@clehner
Copy link
Contributor

clehner commented Feb 24, 2022

Merged with additional relevant changes in #390

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants