Verifying a UCAN in NodeJS

Is anybody aware of a quick hack to create a PEM formatted key from the issuer-did in a ucan?

I want to verify a ucan with the jsonwebtoken library (jsonwebtoken - npm) but it wants to have the key in PEM format.

I tried to borrow the “rsa/verify()” function from “keystore-idb” but realized that it relies heavily on atob, btoa etc. Things that are not existent out of the box in node.

On the other hand Node just recently added support for “subtle”.

I tried to adapt the necessary parts to work with node’s subtle but my key format seems not to be right:

[ERR_INVALID_ARG_TYPE]: The "key" argument must be an instance of CryptoKey. Received an instance of Buffer

Here is how I try to verify the signature:

    const b64PubKey = didToPublicKey(iss);
    const signedData = ucan.split(".").slice(0,2).join(".");
    const signature = ucan.split(".")[2];

    const verifyResult = await verify(
        signedData,
        signature,
        b64PubKey.publicKey,
        8
    )

Thx!

1 Like

As mentioned in chat, this need may overlap with work @benjaminbollen and @dholms are doing on the #cosigner

Daniel wrote the keystore-idb stuff so will be familiar on both sides.

Here is the in progress co-signer GitHub being written in NodeJS GitHub - fission-suite/fil-cosigner

1 Like

sweet, great to know! :slight_smile: We were thinking to have to rewrite some of the webnative lib for nodejs; we might still prefer to because it s experimental Web Crypto API | Node.js v21.7.1 Documentation

the only verification code for UCAN web token is either in webnative (for browser, using crypto subtle), (or a golang and haskell impl)

what is the service you have in mind?

We have a small “directory-server” where every new user registers his/her profile (at the first signup and then on every update). You can think of it like an aggregator that collects all the omo-profiles out there.

First I used a simple http-api to which the new users submits their fisssion username. The server would then query the DNSLink to resolve the FS-root and there look for a profile.json at a specific path.

Since we need the directory for an invite-process (people could be standing right next to each other when performing the invite), the directory update should be as fast as possible. Of course it always takes a while to update the DNSLink so I looked at the DNSLink update logic in “data-root.ts” and decided to push the profile information directly to the server just like the new fs-root-cid is sent to the dns link update service.

On the server I then need to validate the UCAN to check if I got a legitimate request.

1 Like

I already “ported” the relevant parts to verify a signature (as far as I can tell by looking at the implementation in keystore-idb) but currently have troubles with node-subtle’s importKey() function.

When importing with the following parameters I get an error:0D07207B:asn1 encoding routines:ASN1_get_object:header too long error.

RsaHashedImportParams: {
alg: RSASSA-PKCS1-v1_5,
hash: SHA-256
}
format: SPKI
keyUsages: ["verify"]

The public key is retrieved by “didToPublicKey()”.
I noticed that the key is slightly shorter than one generated by OpenSSL.
didToPublicKey() yields 274 bytes while OpenSSL generates a file with 294 byte in DER-Format.
The key which I’ve extracted from the DID also cannot be parsed by openssl asn1parse so there might be only a problem with the format in the end?!

Got it working. Lost some bytes on the way…

I will clean up the mess and then post a link to the repo. Would be cool if someone could have a look at it to make sure that it doesn’t contain too obvious errors :sweat_smile:

3 Likes

great work! I will definitely have a look!