generated from tkuhrt/os-template
-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Alexander Sukhachev <[email protected]>
- Loading branch information
Showing
17 changed files
with
696 additions
and
163 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,13 +2,14 @@ | |
name = "sd-jwt-generate" | ||
version = "0.1.0" | ||
edition = "2021" | ||
authors = ["Abdulbois Tursunov <[email protected]>", "Alexander Sukhachev <[email protected]>"] | ||
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
|
||
[dependencies] | ||
clap = { version = "4.4.10", features = ["derive"] } | ||
serde = { version = "1.0.193", features = ["derive"] } | ||
serde_yaml = "0.9.27" | ||
serde_json = "1.0.108" | ||
serde_json = { version = "1.0.113", features = ["preserve_order"] } | ||
jsonwebtoken = "9.1" | ||
sd-jwt-rs = {path = "./.."} | ||
sd-jwt-rs = {path = "./..", features = ["mock_salts"]} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
# SD-JWT Interop tool | ||
|
||
This tool is used to verify interoperability between the `sd-jwt-rust` and `sd-jwt-python` implementations of the [IETF SD-JWT specification](https://datatracker.ietf.org/doc/draft-ietf-oauth-selective-disclosure-jwt/). | ||
|
||
## How does the Interop tool work? | ||
|
||
The main idea is to generate data structures (SDJWT/presentation/verified claims) using both implementations and compare them. | ||
|
||
The `sd-jwt-python` is used to generate artifacts based on input data (`specification.yml`) and store them as files. | ||
The interop tool (based on `sd-jwt-rust`) is used to generate artifacts using the same specification file, load artifacts stored in files by `sd-jwt-python` and compare them. The interop tool doesn't store any files on filesystem. | ||
|
||
There are some factors that make impossible to compare data due to non-equivalence data generated by different implementations: | ||
|
||
- Using random 'salt' in each run that make results different even though they are generated by the same implementation. | ||
- Not equivalent json-serialized strings (different number of spaces) generated under the hood of the different implementations. | ||
- Using 'decoy' digests in the SD-JWT payload. | ||
|
||
In order to reach reproducibility and equivalence of the values generated by both implementations it is required to use the same input data (issuer private key, user claims, etc.) and to get rid of some non-deterministic values during data generating (values of 'salt', for example). | ||
|
||
### Deterministic 'salt' | ||
|
||
In order to make it possible to get reproducible result each run it's required to use deterministic values of 'salt' used in internal algorithms. The `sd-jwt-python` project implements such behavior for test purposes. | ||
|
||
In order to use the same set of 'salt' values by the `sd-jwt-rust` project Python-implementation stores values in the `claims_vs_salts.json` file as artifact. The Interop tool loads values from the file and use it instead of random generated values (see the `mock_salts` feature). | ||
|
||
|
||
### Similar json serialization | ||
|
||
In order to have the same json-strings used under the hood of the both implementations there is some code that gets rid of different number of spaces: | ||
|
||
```rust | ||
value_str = value_str | ||
.replace(":[", ": [") | ||
.replace(',', ", ") | ||
.replace("\":", "\": ") | ||
.replace("\": ", "\": "); | ||
``` | ||
|
||
### 'Decoy' SD items | ||
|
||
In order to make it possible to compare `SD-JWT` payloads that contains [decoy](https://www.ietf.org/archive/id/draft-ietf-oauth-selective-disclosure-jwt-07.html#name-decoy-digests) it was decided to detect and remove all `decoy` items from payloads and then compare them. | ||
|
||
|
||
## How to use the interop tool? | ||
|
||
1. Install the prerequisites | ||
2. Clone and build the `sd-jwt-rust` project | ||
3. Clone and build the `sd-jwt-python` project | ||
4. Generate artifacts using the `sd-jwt-python` project | ||
5. Run the interop tool | ||
|
||
### Install the prerequisites | ||
|
||
In order to be able to build both implementations it is required to setup following tools: | ||
|
||
- `Rust`/`cargo` | ||
- `poetry` | ||
|
||
|
||
### Clone and build the `sd-jwt-rust` project | ||
|
||
```shell | ||
git clone [email protected]:openwallet-foundation-labs/sd-jwt-rust.git | ||
cd sd-jwt-rust/generate | ||
cargo build | ||
``` | ||
|
||
|
||
### Clone and build the `sd-jwt-python` project | ||
|
||
Once the project repo is cloned to local directory it is necessary to apply special patch. | ||
This patch is required to have some additional files as artifacts generated by the `sd-jwt-python` project. | ||
|
||
Files: | ||
|
||
- `claims_vs_salts.json` file contains values of so called 'salt' that have been used during `SDJWT` issuance. | ||
- `issuer_key.pem` file contains the issuer's private key. | ||
- `issuer_public_key.pem` file contains the issuer's public key. | ||
- `holder_key.pem` file contains the holder's private key. | ||
|
||
The files are used to make it possible for this tool to generate the same values of artifacts (SDJWT payload/SDJWT claims/presentation/verified claims) that are generated by `sd-jwt-python`. | ||
|
||
|
||
```shell | ||
git clone [email protected]:openwallet-foundation-labs/sd-jwt-python.git | ||
cd sd-jwt-python | ||
|
||
# apply the patch | ||
git apply ../sd-jwt-rust/generate/sd_jwt_python.patch | ||
|
||
# build | ||
poetry install && poetry build | ||
``` | ||
|
||
|
||
|
||
### Generate artifacts using the `sd-jwt-python` project | ||
|
||
```shell | ||
pushd sd-jwt-python/tests/testcases && poetry run ../../src/sd_jwt/bin/generate.py -- example && popd | ||
pushd sd-jwt-python/examples && poetry run ../src/sd_jwt/bin/generate.py -- example && popd | ||
``` | ||
|
||
|
||
### Run the interop tool | ||
|
||
```shell | ||
cd sd-jwt-rust/generate | ||
sd_jwt_py="../../sd-jwt-python" | ||
for cases_dir in $sd_jwt_py/examples $sd_jwt_py/tests/testcases; do | ||
for test_case_dir in $(ls $cases_dir); do | ||
if [[ -d $cases_dir/$test_case_dir ]]; then | ||
./target/debug/sd-jwt-generate -p $cases_dir/$test_case_dir | ||
fi | ||
done | ||
done | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
diff --git a/.gitignore b/.gitignore | ||
index 1874e26..72ff453 100644 | ||
--- a/.gitignore | ||
+++ b/.gitignore | ||
@@ -157,7 +157,7 @@ cython_debug/ | ||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore | ||
# and can be added to the global gitignore or merged into this file. For a more nuclear | ||
# option (not recommended) you can uncomment the following to ignore the entire idea folder. | ||
-#.idea/ | ||
+.idea/ | ||
|
||
|
||
# Ignore output of test cases except for specification.yml | ||
diff --git a/pyproject.toml b/pyproject.toml | ||
index 4294e64..47c9281 100644 | ||
--- a/pyproject.toml | ||
+++ b/pyproject.toml | ||
@@ -12,7 +12,7 @@ jwcrypto = ">=1.3.1" | ||
pyyaml = ">=5.4" | ||
|
||
[tool.poetry.group.dev.dependencies] | ||
-flake8 = "^6.0.0" | ||
+# flake8 = "^6.0.0" | ||
black = "^23.3.0" | ||
|
||
[build-system] | ||
diff --git a/src/sd_jwt/bin/generate.py b/src/sd_jwt/bin/generate.py | ||
index ad00641..d0299ea 100755 | ||
--- a/src/sd_jwt/bin/generate.py | ||
+++ b/src/sd_jwt/bin/generate.py | ||
@@ -105,12 +105,36 @@ def generate_test_case_data(settings: Dict, testcase_path: Path, type: str): | ||
|
||
# Write the test case data to the directory of the test case | ||
|
||
+ claims_vs_salts = [] | ||
+ for disclosure in sdjwt_at_issuer.ii_disclosures: | ||
+ claims_vs_salts.append(disclosure.salt) | ||
+ | ||
_artifacts = { | ||
"user_claims": ( | ||
remove_sdobj_wrappers(testcase["user_claims"]), | ||
"User Claims", | ||
"json", | ||
), | ||
+ "issuer_key": ( | ||
+ demo_keys["issuer_key"].export_to_pem(True, None).decode("utf-8"), | ||
+ "Issuer private key", | ||
+ "pem", | ||
+ ), | ||
+ "issuer_public_key": ( | ||
+ demo_keys["issuer_public_key"].export_to_pem(False, None).decode("utf-8"), | ||
+ "Issuer public key", | ||
+ "pem", | ||
+ ), | ||
+ "holder_key": ( | ||
+ demo_keys["holder_key"].export_to_pem(True, None).decode("utf-8"), | ||
+ "Issuer private key", | ||
+ "pem", | ||
+ ), | ||
+ "claims_vs_salts": ( | ||
+ claims_vs_salts, | ||
+ "Claims with Salts", | ||
+ "json", | ||
+ ), | ||
"sd_jwt_payload": ( | ||
sdjwt_at_issuer.sd_jwt_payload, | ||
"Payload of the SD-JWT", | ||
diff --git a/src/sd_jwt/disclosure.py b/src/sd_jwt/disclosure.py | ||
index a9727c4..d1f983a 100644 | ||
--- a/src/sd_jwt/disclosure.py | ||
+++ b/src/sd_jwt/disclosure.py | ||
@@ -15,11 +15,11 @@ class SDJWTDisclosure: | ||
self._hash() | ||
|
||
def _hash(self): | ||
- salt = self.issuer._generate_salt() | ||
+ self._salt = self.issuer._generate_salt() | ||
if self.key is None: | ||
- data = [salt, self.value] | ||
+ data = [self._salt, self.value] | ||
else: | ||
- data = [salt, self.key, self.value] | ||
+ data = [self._salt, self.key, self.value] | ||
|
||
self._json = dumps(data).encode("utf-8") | ||
|
||
@@ -30,6 +30,10 @@ class SDJWTDisclosure: | ||
def hash(self): | ||
return self._hash | ||
|
||
+ @property | ||
+ def salt(self): | ||
+ return self._salt | ||
+ | ||
@property | ||
def b64(self): | ||
return self._raw_b64 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.