diff --git a/pyeudiw/satosa/backend.py b/pyeudiw/satosa/backend.py index 5d4b84a3..b3777ca1 100644 --- a/pyeudiw/satosa/backend.py +++ b/pyeudiw/satosa/backend.py @@ -23,7 +23,7 @@ from pyeudiw.tools.qr_code import QRCode from pyeudiw.tools.mobile import is_smartphone from pyeudiw.tools.utils import iat_now -from pyeudiw.tools.sd_jwt import verify_sd_jwt +from pyeudiw.sd_jwt import verify_sd_jwt logger = logging.getLogger("openid4vp_backend") diff --git a/pyeudiw/tools/sd_jwt.py b/pyeudiw/sd_jwt/__init__.py similarity index 82% rename from pyeudiw/tools/sd_jwt.py rename to pyeudiw/sd_jwt/__init__.py index 96d1a478..955821b8 100644 --- a/pyeudiw/tools/sd_jwt.py +++ b/pyeudiw/sd_jwt/__init__.py @@ -5,8 +5,8 @@ from sd_jwt.utils.formatting import textwrap_json from sd_jwt.utils.yaml_specification import load_yaml_specification -from .utils import iat_now -from ..jwk import JWK +from pyeudiw.tools.utils import iat_now +from pyeudiw.jwk import JWK def _adapt_keys(settings: dict, issuer_key: JWK, holder_key: JWK): keys = { @@ -19,29 +19,27 @@ def _adapt_keys(settings: dict, issuer_key: JWK, holder_key: JWK): return get_jwk(keys, settings["no_randomness"], None) -def issue_sd_jwt(claims: dict, settings: dict, issuer_key: JWK, holder_key: JWK) -> str: +def issue_sd_jwt(user_claims_path: str, settings: dict, issuer_key: JWK, holder_key: JWK) -> str: + user_claims = load_yaml_specification(user_claims_path) + claims = { "iss": settings["issuer"], "iat": iat_now(), "exp": iat_now() + (settings["default_exp"] * 60) # in seconds } - claims.update(claims) - - specification = load_yaml_specification(settings["specification_file"]) - - use_decoys = specification.get("add_decoy_claims", False) - + user_claims.update(claims) + use_decoys = user_claims.get("add_decoy_claims", False) adapted_keys = _adapt_keys(settings, issuer_key, holder_key) SDJWTIssuer.unsafe_randomness = settings["no_randomness"] sdjwt_at_issuer = SDJWTIssuer( - claims, + user_claims, adapted_keys["issuer_key"], - adapted_keys["holder_key"] if specification.get("key_binding", False) else None, + adapted_keys["holder_key"], add_decoy_claims=use_decoys, ) - + return {"jws": textwrap_json(sdjwt_at_issuer.serialized_sd_jwt), "issuance": sdjwt_at_issuer.sd_jwt_issuance} def verify_sd_jwt(sd_jwt_presentation: str, settings: dict, issuer_key: JWK, holder_key: JWK): diff --git a/pyeudiw/tests/tools/specifications.yml b/pyeudiw/tests/tools/specifications.yml index 46b46c02..49dc82e2 100644 --- a/pyeudiw/tests/tools/specifications.yml +++ b/pyeudiw/tests/tools/specifications.yml @@ -1,17 +1,16 @@ user_claims: - !sd sub: john_doe_42 - !sd given_name: John - !sd family_name: Doe - !sd email: johndoe@example.com - !sd phone_number: +1-202-555-0101 - !sd address: - street_address: 123 Main St - locality: Anytown - region: Anystate - country: US - !sd birthdate: "1940-01-01" + # Make only first two elements SD - this array will have three elements in the resulting SD-JWT, first two hidden + nationalities: + - !sd "US" + - !sd "CA" + - "DE" holder_disclosed_claims: - { "given_name": null, "family_name": null, "address": {} } + nationalities: + - False + - True -key_binding: True \ No newline at end of file +expect_verified_user_claims: + nationalities: + - "CA" + - "DE" \ No newline at end of file diff --git a/pyeudiw/tests/tools/test_sd_jwt.py b/pyeudiw/tests/tools/test_sd_jwt.py index 3edad4f7..27c38c59 100644 --- a/pyeudiw/tests/tools/test_sd_jwt.py +++ b/pyeudiw/tests/tools/test_sd_jwt.py @@ -1,7 +1,7 @@ import pytest from pyeudiw.jwk import JWK -from pyeudiw.tools.sd_jwt import (issue_sd_jwt, verify_sd_jwt, _adapt_keys) +from pyeudiw.sd_jwt import (issue_sd_jwt, verify_sd_jwt, _adapt_keys) from sd_jwt.utils.yaml_specification import load_yaml_specification @@ -12,8 +12,10 @@ def test_issue_sd_jwt(): issuer_jwk = JWK() holder_jwk = JWK() + user_claims_path = "./pyeudiw/tests/tools/specifications.yml" + issue_sd_jwt( - {"given_name": "Alfred"}, + user_claims_path, {"issuer": "http://test.com", "default_exp": 60, "specification_file": "./pyeudiw/tests/tools/specifications.yml", "no_randomness": True}, issuer_jwk, holder_jwk @@ -23,8 +25,10 @@ def test_verify_sd_jwt(): issuer_jwk = JWK() holder_jwk = JWK() + user_claims_path = "./pyeudiw/tests/tools/specifications.yml" + issued_jwt = issue_sd_jwt( - {"given_name": "Alfred"}, + user_claims_path, {"issuer": "http://test.com", "default_exp": 60, "specification_file": "./pyeudiw/tests/tools/specifications.yml", "no_randomness": True}, issuer_jwk, holder_jwk @@ -41,18 +45,14 @@ def test_verify_sd_jwt(): serialization_format="compact", ) sdjwt_at_holder.create_presentation( - testcase["holder_disclosed_claims"], - "" - if testcase.get("key_binding", False) - else None, - "http://test.com" - if testcase.get("key_binding", False) - else None, + {}, + None, + None, adapted_keys["holder_key"] if testcase.get("key_binding", False) else None, ) print(sdjwt_at_holder.sd_jwt_presentation) - + verified_payload = verify_sd_jwt( sdjwt_at_holder.sd_jwt_presentation, { @@ -62,7 +62,4 @@ def test_verify_sd_jwt(): "specification_file": "./pyeudiw/tests/tools/specifications.yml", "no_randomness": True, "key_binding_nonce": "" - }, issuer_jwk, holder_jwk) - - print(verified_payload) - \ No newline at end of file + }, issuer_jwk, holder_jwk) \ No newline at end of file