Skip to content

Commit

Permalink
fix(waku_keystore): sigsegv on different appInfo (#2654)
Browse files Browse the repository at this point in the history
* fix(waku_keystore): sigsegv on different appInfo

* fix: field specific errors

* fix: more verbose error logs
  • Loading branch information
rymnc authored May 1, 2024
1 parent d5e0e4a commit 5dd645c
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 8 deletions.
57 changes: 57 additions & 0 deletions tests/test_waku_keystore.nim
Original file line number Diff line number Diff line change
Expand Up @@ -246,3 +246,60 @@ procSuite "Credentials test suite":
check:
recoveredCredentialsRes.isErr()
recoveredCredentialsRes.error.kind == KeystoreCredentialNotFoundError

test "if a keystore exists, but the keystoreQuery doesn't match it":
let filepath = "./testAppKeystore.txt"
defer:
removeFile(filepath)

# We generate random identity credentials (inter-value constrains are not enforced, otherwise we need to load e.g. zerokit RLN keygen)
let
idTrapdoor = randomSeqByte(rng[], 32)
idNullifier = randomSeqByte(rng[], 32)
idSecretHash = randomSeqByte(rng[], 32)
idCommitment = randomSeqByte(rng[], 32)
idCredential = IdentityCredential(
idTrapdoor: idTrapdoor,
idNullifier: idNullifier,
idSecretHash: idSecretHash,
idCommitment: idCommitment,
)

# We generate two distinct membership groups
let contract = MembershipContract(
chainId: "5", address: "0x0123456789012345678901234567890123456789"
)
let index = MembershipIndex(1)
var membershipCredential = KeystoreMembership(
membershipContract: contract, treeIndex: index, identityCredential: idCredential
)

let password = "%m0um0ucoW%"

let keystoreRes = addMembershipCredentials(
path = filepath,
membership = membershipCredential,
password = password,
appInfo = testAppInfo,
)

assert(keystoreRes.isOk(), $keystoreRes.error)

let badTestAppInfo =
AppInfo(application: "_bad_test_", appIdentifier: "1234", version: "0.1")

# We test retrieval of credentials.
let membershipQuery = KeystoreMembership(membershipContract: contract)

let recoveredCredentialsRes = getMembershipCredentials(
path = filepath,
password = password,
query = membershipQuery,
appInfo = badTestAppInfo,
)

check:
recoveredCredentialsRes.isErr()
recoveredCredentialsRes.error.kind == KeystoreJsonValueMismatchError
recoveredCredentialsRes.error.msg ==
"Application does not match. Expected '_bad_test_' but got 'test'"
51 changes: 43 additions & 8 deletions waku/waku_keystore/keystore.nim
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ proc loadAppKeystore*(
): KeystoreResult[JsonNode] =
## Load and decode JSON keystore from pathname
var data: JsonNode
var matchingAppKeystore: JsonNode

# If no keystore exists at path we create a new empty one with passed keystore parameters
if fileExists(path) == false:
Expand Down Expand Up @@ -77,14 +76,45 @@ proc loadAppKeystore*(

# We check if parsed json contains the relevant keystore credentials fields and if these are set to the passed parameters
# (note that "if" is lazy, so if one of the .contains() fails, the json fields contents will not be checked and no ResultDefect will be raised due to accessing unavailable fields)
if data.hasKeys(["application", "appIdentifier", "credentials", "version"]) and
data["application"].getStr() == appInfo.application and
data["appIdentifier"].getStr() == appInfo.appIdentifier and
data["version"].getStr() == appInfo.version:
if not data.hasKeys(["application", "appIdentifier", "credentials", "version"]):
return err(
AppKeystoreError(
kind: KeystoreJsonKeyError, msg: "Missing required fields in keystore"
)
)

if data["application"].getStr() != appInfo.application:
return err(
AppKeystoreError(
kind: KeystoreJsonValueMismatchError,
msg:
"Application does not match. Expected '" & appInfo.application &
"' but got '" & data["application"].getStr() & "'",
)
)

if data["appIdentifier"].getStr() != appInfo.appIdentifier:
return err(
AppKeystoreError(
kind: KeystoreJsonValueMismatchError,
msg:
"AppIdentifier does not match. Expected '" & appInfo.appIdentifier &
"' but got '" & data["appIdentifier"].getStr() & "'",
)
)

if data["version"].getStr() != appInfo.version:
return err(
AppKeystoreError(
kind: KeystoreJsonValueMismatchError,
msg:
"Version does not match. Expected '" & appInfo.version & "' but got '" &
data["version"].getStr() & "'",
)
)
# We return the first json keystore that matches the passed app parameters
# We assume a unique kesytore with such parameters is present in the file
matchingAppKeystore = data
break
return ok(data)
# TODO: we might continue rather than return for some of these errors
except JsonParsingError:
return
Expand All @@ -101,7 +131,12 @@ proc loadAppKeystore*(
except IOError:
return err(AppKeystoreError(kind: KeystoreIoError, msg: getCurrentExceptionMsg()))

return ok(matchingAppKeystore)
return err(
AppKeystoreError(
kind: KeystoreKeystoreDoesNotExist,
msg: "No keystore found for the passed parameters",
)
)

# Adds a membership credential to the keystore matching the application, appIdentifier and version filters.
proc addMembershipCredentials*(
Expand Down
1 change: 1 addition & 0 deletions waku/waku_keystore/protocol_types.nim
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ type
KeystoreOsError = "keystore error: OS specific error"
KeystoreIoError = "keystore error: IO specific error"
KeystoreJsonKeyError = "keystore error: fields not present in JSON"
KeystoreJsonValueMismatchError = "keystore error: JSON value mismatch"
KeystoreJsonError = "keystore error: JSON encoder/decoder error"
KeystoreKeystoreDoesNotExist = "keystore error: file does not exist"
KeystoreCreateKeystoreError = "Error while creating application keystore"
Expand Down

0 comments on commit 5dd645c

Please sign in to comment.