WebOfTrust / signify-ts

Typescript prototype of Simple KERI for Web Apps
https://weboftrust.github.io/signify-ts/
Apache License 2.0
16 stars 30 forks source link

signify-ts should throw exception when running in WASM #284

Open edeykholt opened 5 days ago

edeykholt commented 5 days ago

Summary: I ran into two issues when attempting to call into signify-ts running in a browser with C# Blazor WASM. I suspect these are just the tip of an iceberg. Instead of an epic chasing down all these issues, a future WASM-friendly interface to KERIA could be written. For now, I recommend signify-ts detects when it is running in WASM and throws an exception "WASM not supported".

The issues for me involved calls into SignifyClient createSignedRequest(), where the returned Request was different in my code than via signify-browser-extension.

Works from signify-browser-extension: selected RequestHeaders as presented in Chrome DevTools / Headers:

:authority: reg-api-dev.rootsid.cloud
:method: GET
:path: /status/EO0KSgpgvjNFoc8KoFfb0qgjbrVieMVbBhNit7ZtEue3
:scheme: https
accept: */*
accept-encoding: gzip, deflate, br, zstd
accept-language: en-US,en;q=0.9
origin: https://reg-pilot-webapp-test.rootsid.cloud
priority: u=1, i
referer: https://reg-pilot-webapp-test.rootsid.cloud/
sec-ch-ua: "Google Chrome";v="129", "Not=A?Brand";v="8", "Chromium";v="129"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
sec-fetch-dest: empty
sec-fetch-mode: cors
sec-fetch-site: same-site
signature: indexed="?0";signify="0BDPdUJ9OP2d1Ge_mH7uTDV2JS8B5kLM4dJMBaIRshxH2Pww8YgYf_QhbFpqXaWklWQkHUjVQYIkvAFW3BV5sjEB"
signature-input: signify=("@method" "@path" "signify-resource" "signify-timestamp");created=1729035722;keyid="BJF5YenWeqMPGU2iL2hsn9D8PSGXRDXSZbM7Znvh1XvI";alg="ed25519"
signify-resource: EO0KSgpgvjNFoc8KoFfb0qgjbrVieMVbBhNit7ZtEue3
signify-timestamp: 2024-10-15T23:42:02.812000+00:00
user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36

Broken when calling via WASM. Output is the same except for the following:

signature-input: signify=("@method" "@path" "signify-resource" "signify-timestamp");created=1729035130;keyid="DJF5YenWeqMPGU2iL2hsn9D8PSGXRDXSZbM7Znvh1XvI";alg="ed25519"
signify-timestamp: 2024-10-15T23:32:10.19+00:00

The underlying bugs are manifest as follows: 1) The first character of the keyid is different: B versus D.
2) Note the timestamps are formatted differently, which may or may not be a problem here, but will be elsewhere. Previously, when my machine was not set to UTC timezone, it presented a timezone offset here.

ChatGPT offers the likely issues: 1. Locale-Specific String and Number Formatting Problem: JavaScript has built-in support for locale-specific string and number formatting (e.g., Intl.NumberFormat, toLocaleString). WASM does not directly support this, so any locale-specific transformations need to be handled outside the WASM environment. Typical Bugs: Incorrectly formatted numbers, dates, or strings when running in a WASM environment. Inconsistent behavior for users in different locales or regions. Solution: Perform locale-specific operations in JavaScript and pass the formatted results to WASM. Ensure that your WASM logic can handle plain, locale-neutral data formats (e.g., ISO date strings, numbers without localized separators).

See typescript such as here: https://github.com/WebOfTrust/signify-ts/blob/1b747f85e17a5adeae859436cc535478d2aec8f7/src/keri/app/exchanging.ts#L163

2. String Manipulation Bugs. Date and Time Handling Problem: JavaScript has a rich Date object that provides various utilities for parsing, formatting, and manipulating dates. WebAssembly, however, doesn’t have direct access to these objects, so any date manipulation must be done through interop or implemented within WASM manually. Typical Bugs: Incorrect date and time calculations due to timezone differences or locale formatting issues. Discrepancies in date parsing when using methods like Date.parse or new Date() because WASM does not inherently understand JavaScript date formats. Solution: Handle all date parsing and formatting in JavaScript, then pass the processed results to WASM as a timestamp or string. If doing date manipulation within WASM, ensure you’re using compatible libraries or handle conversions explicitly.

See the potential issue here: https://github.com/WebOfTrust/signify-ts/blob/1b747f85e17a5adeae859436cc535478d2aec8f7/src/keri/core/authing.ts#L107

Rather than fix these anytime soon, I suggest an update be made early in the signify-ts client workflow to run a check such as the following, then throw an exception if running in WASM. This code was suggested by ChatGPT and not tested:

function isRunningWithWASM() { 
try { // This will throw an error if WebAssembly memory is not accessible 
   const memory = new WebAssembly.Memory({ initial: 1 }); 
   memory.grow(1); 
   return true; 
} catch (e) { 
   return false; }
} 
daidoji commented 5 days ago

Oh maybe that code snippet will work to sniff the env but

  1. WASM should have access to the js runtime functions. At least when I was doing the Rust/wasm stuff they had a method in rust to call js functions from Rust directly.
  2. B is a non-transferable Ed25519 key, D is a transferable key. How would wasm be changing that call?
  3. The only difference in time format is that its not giving the full precision for milliseconds that js native is?

Also this code you linked is a bug. Not sure why someone felt the need to do that. Z is valid RFC 3339 datetime offset.

See https://www.rfc-editor.org/rfc/rfc3339.txt

edeykholt commented 5 days ago

@daidoji. I should have mentioned I was testing the two browser extensions (signify-browser-extension and KERI Auth) with
https://reg-pilot-webapp-test.rootsid.cloud. After the flow with KERI Auth eventually generated the request header the requested page returned a failed status:

EO0KSgpgvjNFoc8KoFfb0qgjbrVieMVbBhNit7ZtEue3 signature (Cigar) verification failed on encoding of request data https://reg-pilot-webapp-test.rootsid.cloud/status

This error might be coming from the https://github.com/GLEIF-IT/vlei-verifier components. Since the header values of signify-timestamp and signature-input string values are different, the header verification (in the vlei-verifier component?) fails for that fetch of the /status page.

As to your questions:

  1. WASM does indeed have access to the js functions, but they don't all behave the same, in the ways I referenced.
  2. Since I believe that the keyid value in signify-ts is being calculated with string manipulation or concatenation with the HD key path, I think that is where the bug is. It might be the string manipulation are different because of byte boundaries. I don't know.
  3. The date issue here might be in the string value, since that is what is contributing to the signature-input. However, dates are used all over for expiry checking, and they might not all be tolerant to RFC 3339 format differences. Posix time is used in many places, so having the precision across these two encodings matters when represented as strings.

If the code maintainers prefer this issue is split into multiple, I'm happy to do that, but I'm going to stop testing signify-ts in WASM soon.

daidoji commented 5 days ago

So signify isn't spec compliant? That should probably be a bug. Times in KERI are all supposed to be RFC 3339 compliant. Both representations are compliant to the spec but mean slightly different things in 3339.

Its weird that C# does that for WASM because Rust doesn't.

edeykholt commented 4 days ago

Note that several of the methods on SignifyClient work just fine in browser WASM, including new(), boot(), connect(), state(), identifiers().create(), identifiers().list(), identifiers.get(), agent.pre, and state(). In the near term, I'll continue calling these via WASM.