Skip to content

Commit

Permalink
Merge branch 'main' into danielfett/kb-jwt-hash
Browse files Browse the repository at this point in the history
  • Loading branch information
danielfett authored Oct 4, 2023
2 parents d39e47f + 23f9d1d commit 0b1c5e9
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 8 deletions.
4 changes: 3 additions & 1 deletion src/sd_jwt/bin/generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ def generate_test_case_data(settings: Dict, testcase_path: Path, type: str):
use_decoys = testcase.get("add_decoy_claims", False)
serialization_format = testcase.get("serialization_format", "compact")
include_default_claims = testcase.get("include_default_claims", True)
extra_header_parameters = testcase.get("extra_header_parameters", None)

claims = {}
if include_default_claims:
Expand All @@ -58,6 +59,7 @@ def generate_test_case_data(settings: Dict, testcase_path: Path, type: str):
demo_keys["holder_key"] if testcase.get("key_binding", False) else None,
add_decoy_claims=use_decoys,
serialization_format=serialization_format,
extra_header_parameters=extra_header_parameters,
)

### Produce SD-JWT-R for selected example
Expand All @@ -81,7 +83,7 @@ def generate_test_case_data(settings: Dict, testcase_path: Path, type: str):

# Define a function to check the issuer and retrieve the
# matching public key
def cb_get_issuer_key(issuer):
def cb_get_issuer_key(issuer, header_parameters):
# Do not use in production - this allows to use any issuer name for demo purposes
if issuer == claims.get("iss", None):
return demo_keys["issuer_public_key"]
Expand Down
2 changes: 1 addition & 1 deletion src/sd_jwt/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def __init__(self, error_location: any):


class SDJWTCommon:
SD_JWT_HEADER = None # "sd+jwt"
SD_JWT_TYP_HEADER = None # "sd+jwt"
KB_JWT_TYP_HEADER = "kb+jwt"
JWS_KEY_DISCLOSURES = "disclosures"
JWS_KEY_KB_JWT = "kb_jwt"
Expand Down
8 changes: 6 additions & 2 deletions src/sd_jwt/issuer.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ def __init__(
sign_alg=None,
add_decoy_claims: bool = False,
serialization_format: str = "compact",
extra_header_parameters: Dict = None,
):
super().__init__(serialization_format=serialization_format)

Expand All @@ -44,6 +45,7 @@ def __init__(
self._holder_key = holder_key
self._sign_alg = sign_alg or DEFAULT_SIGNING_ALG
self._add_decoy_claims = add_decoy_claims
self._extra_header_parameters = extra_header_parameters

self.ii_disclosures = []
self.decoy_digests = []
Expand Down Expand Up @@ -168,8 +170,10 @@ def _create_signed_jws(self):

# Assemble protected headers
_protected_headers = {"alg": self._sign_alg}
if self.SD_JWT_HEADER:
_protected_headers["typ"] = self.SD_JWT_HEADER
if self.SD_JWT_TYP_HEADER:
_protected_headers["typ"] = self.SD_JWT_TYP_HEADER
if self._extra_header_parameters:
_protected_headers.update(self._extra_header_parameters)

self.sd_jwt.add_signature(
self._issuer_key,
Expand Down
5 changes: 3 additions & 2 deletions src/sd_jwt/verifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class SDJWTVerifier(SDJWTCommon):
def __init__(
self,
sd_jwt_presentation: str,
cb_get_issuer_key: Callable[[str], str],
cb_get_issuer_key: Callable[[str, Dict], str],
expected_aud: Union[str, None] = None,
expected_nonce: Union[str, None] = None,
serialization_format: str = "compact",
Expand Down Expand Up @@ -58,7 +58,8 @@ def _verify_sd_jwt(
parsed_input_sd_jwt.deserialize(self._unverified_input_sd_jwt)

unverified_issuer = self._unverified_input_sd_jwt_payload.get("iss", None)
issuer_public_key = cb_get_issuer_key(unverified_issuer)
unverified_header_parameters = parsed_input_sd_jwt.jose_header
issuer_public_key = cb_get_issuer_key(unverified_issuer, unverified_header_parameters)
parsed_input_sd_jwt.verify(issuer_public_key, alg=sign_alg)

self._sd_jwt_payload = loads(parsed_input_sd_jwt.payload.decode("utf-8"))
Expand Down
14 changes: 13 additions & 1 deletion tests/test_disclose_all_shortcut.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ def test_e2e(testcase, settings):
demo_keys = get_jwk(settings["key_settings"], True, seed)
use_decoys = testcase.get("add_decoy_claims", False)
serialization_format = testcase.get("serialization_format", "compact")
extra_header_parameters = testcase.get("extra_header_parameters", None)

# Issuer: Produce SD-JWT and issuance format for selected example

Expand All @@ -23,6 +24,7 @@ def test_e2e(testcase, settings):
demo_keys["holder_key"] if testcase.get("key_binding", False) else None,
add_decoy_claims=use_decoys,
serialization_format=serialization_format,
extra_header_parameters=extra_header_parameters,
)

output_issuance = sdjwt_at_issuer.sd_jwt_issuance
Expand All @@ -32,9 +34,12 @@ def test_e2e(testcase, settings):
output_holder = output_issuance

# Verifier
def cb_get_issuer_key(issuer):
sdjwt_header_parameters = {}
def cb_get_issuer_key(issuer, header_parameters):
sdjwt_header_parameters.update(header_parameters)
return demo_keys["issuer_public_key"]


sdjwt_at_verifier = SDJWTVerifier(
output_holder,
cb_get_issuer_key,
Expand All @@ -52,3 +57,10 @@ def cb_get_issuer_key(issuer):
expected_claims["cnf"] = {"jwk": demo_keys["holder_key"].export_public(as_dict=True)}

assert verified == expected_claims

expected_header_parameters = {
"alg": testcase.get("sign_alg", "ES256")
}
expected_header_parameters.update(extra_header_parameters or {})

assert sdjwt_header_parameters == expected_header_parameters
13 changes: 12 additions & 1 deletion tests/test_e2e_testcases.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ def test_e2e(testcase, settings):
demo_keys = get_jwk(settings["key_settings"], True, seed)
use_decoys = testcase.get("add_decoy_claims", False)
serialization_format = testcase.get("serialization_format", "compact")
extra_header_parameters = testcase.get("extra_header_parameters", None)

# Issuer: Produce SD-JWT and issuance format for selected example

Expand All @@ -23,6 +24,7 @@ def test_e2e(testcase, settings):
demo_keys["holder_key"] if testcase.get("key_binding", False) else None,
add_decoy_claims=use_decoys,
serialization_format=serialization_format,
extra_header_parameters=extra_header_parameters,
)

output_issuance = sdjwt_at_issuer.sd_jwt_issuance
Expand All @@ -45,7 +47,9 @@ def test_e2e(testcase, settings):
output_holder = sdjwt_at_holder.sd_jwt_presentation

# Verifier
def cb_get_issuer_key(issuer):
sdjwt_header_parameters = {}
def cb_get_issuer_key(issuer, header_parameters):
sdjwt_header_parameters.update(header_parameters)
return demo_keys["issuer_public_key"]

sdjwt_at_verifier = SDJWTVerifier(
Expand All @@ -68,3 +72,10 @@ def cb_get_issuer_key(issuer):
}

assert verified == expected_claims

expected_header_parameters = {
"alg": testcase.get("sign_alg", "ES256")
}
expected_header_parameters.update(extra_header_parameters or {})

assert sdjwt_header_parameters == expected_header_parameters
33 changes: 33 additions & 0 deletions tests/testcases/header_mod/specification.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
user_claims:
!sd sub: john_doe_42
!sd given_name: John
!sd family_name: Doe
!sd email: [email protected]
!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"

holder_disclosed_claims:
given_name: true
family_name: true
address: true

extra_header_parameters:
kid: 42

expect_verified_user_claims:
given_name: John
family_name: Doe
address:
street_address: 123 Main St
locality: Anytown
region: Anystate
country: US

key_binding: True

serialization_format: compact

0 comments on commit 0b1c5e9

Please sign in to comment.