Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support for vc+sd-jwt #273

Merged
merged 36 commits into from
Oct 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
3b1b051
sd-jwt format regexp + test + linting
Zicchio Sep 4, 2024
63bfd55
wip: authn response processing
Zicchio Sep 6, 2024
4361310
wip: vc+sd-jwt schema
Zicchio Sep 6, 2024
3b1aa48
wip: vc+sd-jwt
Zicchio Sep 16, 2024
233b9b8
wip: unit test redo
Zicchio Sep 16, 2024
0482d57
wip: test for vc+sd-jwt
Zicchio Sep 16, 2024
1b1f80a
fix: miscellaneous minor fixes
Zicchio Sep 17, 2024
100cc74
chore: cleanup
Zicchio Sep 18, 2024
ce51de3
chore: docs, linting, cleanup
Zicchio Sep 19, 2024
5fa54ed
applied some suggestions
Zicchio Sep 25, 2024
5fd5100
applied come code suggestions
Zicchio Sep 25, 2024
131e338
wip: ideas, brainstoming, etc
Zicchio Sep 26, 2024
290d34f
wip: intent clarification
Zicchio Sep 26, 2024
a1c6833
wip: new trust model and vp interface
Zicchio Sep 26, 2024
650e844
wip: backend configuration example
Zicchio Sep 27, 2024
7dad0a7
wip
Zicchio Sep 27, 2024
a374ad8
wip: stub of response with trust model and vp parser
Zicchio Oct 1, 2024
b6fcd69
wip: unit tests
Zicchio Oct 2, 2024
8459a97
chore: renamed function
Zicchio Oct 2, 2024
af4694f
wip: unit tests, fixes
Zicchio Oct 2, 2024
dab2384
wip: cleanup
elisanp Oct 2, 2024
8a52a2e
wip: cleanup
elisanp Oct 2, 2024
802bbb5
wip: fixes
Zicchio Oct 2, 2024
6b5a6c1
wip: integration test review
Zicchio Oct 2, 2024
cf6f2c4
Merge pull request #1 from Zicchio/dev_vp_trust
Zicchio Oct 3, 2024
f5ddeac
wip: patch get connection
elisanp Oct 3, 2024
10cf886
Merge pull request #2 from Zicchio/dev_vp_trust
elisanp Oct 3, 2024
8bc3a9b
Apply suggestions from code review
Oct 3, 2024
0ecc1f8
Apply suggestions from code review
Oct 3, 2024
1ee3a7b
fix: changed file name
Zicchio Oct 3, 2024
9a199e7
Apply suggestions from code review
Oct 3, 2024
b09ae61
wip: storage layer of trust eval
Zicchio Oct 3, 2024
ea7069d
wip: storage layer + tests fixes
elisanp Oct 11, 2024
4c1511d
wip: integration tests
elisanp Oct 15, 2024
741f06a
wip: fix python 3.12 retrocompatibility + todos
elisanp Oct 17, 2024
3ce699a
wip: exception handling
elisanp Oct 18, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions docs/STORAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,11 +101,22 @@ This classes can be used as references while providing a custom implementation f
"federation" : {
"chain": ARRAY[EC,ES,ES],
"exp": datetime,
"update": datetime
"update": datetime,
"jwks": {
"keys": ARRAY[object]
},
},
"x509": {
"x5c": ARRAY[bytestring(DER), bytestring(DER), bytestring(DER)] -> contains public keys,
"exp": datetime
"exp": datetime,
"jwks": {
"keys": ARRAY[object]
},
},
"direct_trust_sd_jwt_vc": {
"jwks": {
"keys": ARRAY[object]
}
}
"metadata": object
}
Expand Down
109 changes: 45 additions & 64 deletions example/satosa/integration_test/commons.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,18 @@
import base64
from bs4 import BeautifulSoup
import datetime
import requests
import uuid
from typing import Any, Literal
from bs4 import BeautifulSoup
from sd_jwt.holder import SDJWTHolder

from pyeudiw.jwk import JWK
from pyeudiw.jwt import DEFAULT_SIG_KTY_MAP, JWEHelper, JWSHelper
from pyeudiw.jwt import DEFAULT_SIG_KTY_MAP, JWEHelper
from pyeudiw.jwt.utils import decode_jwt_payload
from pyeudiw.presentation_exchange.schemas.oid4vc_presentation_definition import PresentationDefinition
from pyeudiw.sd_jwt import (
# _adapt_keys,
import_ec,
issue_sd_jwt,
load_specification_from_yaml_string
)
from pyeudiw.storage.base_storage import TrustType
from pyeudiw.storage.db_engine import DBEngine
from pyeudiw.tests.federation.base import (
EXP,
Expand All @@ -30,10 +27,11 @@
leaf_wallet_signed,
trust_chain_issuer
)
from pyeudiw.tools.utils import iat_now, exp_from_now
from sd_jwt.holder import SDJWTHolder
from saml2_sp import saml2_request

from saml2_sp import IDP_BASEURL
from settings import (
IDP_BASEURL,
CONFIG_DB,
RP_EID,
its_trust_chain
Expand All @@ -42,25 +40,19 @@
CREDENTIAL_ISSUER_JWK = JWK(leaf_cred_jwk_prot.serialize(private=True))
ISSUER_CONF = {
"sd_specification": """
user_claims:
!sd unique_id: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
!sd given_name: "Mario"
!sd family_name: "Rossi"
!sd birthdate: "1980-01-10"
!sd place_of_birth:
country: "IT"
locality: "Rome"
!sd tax_id_code: "TINIT-XXXXXXXXXXXXXXXX"

holder_disclosed_claims:
{ "given_name": "Mario", "family_name": "Rossi", "place_of_birth": {country: "IT", locality: "Rome"}, "tax_id_code": "TINIT-XXXXXXXXXXXXXXXX" }

key_binding: True
!sd unique_id: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
!sd given_name: "Mario"
!sd family_name: "Rossi"
!sd birthdate: "1980-01-10"
!sd place_of_birth:
country: "IT"
locality: "Rome"
!sd tax_id_code: "TINIT-XXXXXXXXXXXXXXXX"
""",
"issuer": leaf_cred['sub'],
"default_exp": 1024
"default_exp": 1024,
"key_binding": True
}
ISSUER_PRIVATE_JWK = JWK(leaf_cred_jwk.serialize(private=True))
WALLET_PRIVATE_JWK = JWK(leaf_wallet_jwk.serialize(private=True))
WALLET_PUBLIC_JWK = JWK(leaf_wallet_jwk.serialize())

Expand All @@ -71,7 +63,7 @@ def setup_test_db_engine() -> DBEngine:

def apply_trust_settings(db_engine_inst: DBEngine) -> DBEngine:
db_engine_inst.add_trust_anchor(
entity_id=ta_ec['iss'],
entity_id=ta_ec["iss"],
entity_configuration=ta_ec_signed,
exp=EXP
)
Expand All @@ -83,24 +75,32 @@ def apply_trust_settings(db_engine_inst: DBEngine) -> DBEngine:
)

db_engine_inst.add_or_update_trust_attestation(
entity_id=leaf_wallet['iss'],
entity_id=leaf_wallet["iss"],
attestation=leaf_wallet_signed,
exp=datetime.datetime.now().isoformat()
)

db_engine_inst.add_or_update_trust_attestation(
entity_id=leaf_cred['iss'],
entity_id=leaf_cred["iss"],
attestation=leaf_cred_signed,
exp=datetime.datetime.now().isoformat()
)

settings = ISSUER_CONF
db_engine_inst.add_or_update_trust_attestation(
entity_id=settings["issuer"],
trust_type=TrustType.DIRECT_TRUST_SD_JWT_VC,
jwks=leaf_cred_jwk_prot.serialize())
return db_engine_inst

def create_saml_auth_request() -> str:
auth_req_url = f"{saml2_request["headers"][0][1]}&idp_hinting=wallet"
return auth_req_url

def create_issuer_test_data() -> dict[Literal["jws"] | Literal["issuance"], str]:
# create a SD-JWT signed by a trusted credential issuer
settings = ISSUER_CONF
settings['issuer'] = leaf_cred['iss']
settings['default_exp'] = 33
settings["default_exp"] = 33
sd_specification = load_specification_from_yaml_string(
settings["sd_specification"]
)
Expand All @@ -110,73 +110,54 @@ def create_issuer_test_data() -> dict[Literal["jws"] | Literal["issuance"], str]
settings,
CREDENTIAL_ISSUER_JWK,
WALLET_PUBLIC_JWK,
trust_chain=trust_chain_issuer
additional_headers={"typ": "vc+sd-jwt"}
)
return issued_jwt


def create_holder_test_data(issued_jwt: dict[Literal["jws"] | Literal["issuance"], str], request_nonce: str) -> str:
def create_holder_test_data(issued_jwt: dict[Literal["jws"] | Literal["issuance"], str], request_nonce: str, request_aud: str) -> str:
settings = ISSUER_CONF
sd_specification = load_specification_from_yaml_string(
settings["sd_specification"]
)

sdjwt_at_holder = SDJWTHolder(
issued_jwt["issuance"],
serialization_format="compact",
)
sdjwt_at_holder.create_presentation(
claims_to_disclose={
'tax_id_code': "TIN-that",
'given_name': 'Raffaello',
'family_name': 'Mascetti'
"tax_id_code": True,
"given_name": True,
"family_name": True
},
nonce=str(uuid.uuid4()),
aud=str(uuid.uuid4()),
nonce=request_nonce,
aud=request_aud,
sign_alg=DEFAULT_SIG_KTY_MAP[WALLET_PRIVATE_JWK.key.kty],
holder_key=(
import_ec(
WALLET_PRIVATE_JWK.key.priv_key,
kid=WALLET_PRIVATE_JWK.kid
)
if sd_specification.get("key_binding", False)
if settings.get("key_binding", False)
else None
)
)

data = {
"iss": "https://wallet-provider.example.org/instance/vbeXJksM45xphtANnCiG6mCyuU4jfGNzopGuKvogg9c",
"jti": str(uuid.uuid4()),
"aud": "https://relying-party.example.org/callback",
"iat": iat_now(),
"exp": exp_from_now(minutes=5),
"nonce": request_nonce,
"vp": sdjwt_at_holder.sd_jwt_presentation,
}

vp_token = JWSHelper(WALLET_PRIVATE_JWK).sign(
data,
protected={"typ": "JWT"}
)
vp_token = sdjwt_at_holder.sd_jwt_presentation
return vp_token


def create_authorize_response(vp_token: str, state: str, nonce: str, response_uri: str) -> str:
# take relevant information from RP's entity configuration
def create_authorize_response(vp_token: str, state: str, response_uri: str) -> str:
# Extract public key from RP's entity configuration
client = requests.Session()
rp_ec_jwt = client.get(
f'{IDP_BASEURL}/OpenID4VP/.well-known/openid-federation',
f"{IDP_BASEURL}/OpenID4VP/.well-known/openid-federation",
verify=False
).content.decode()
rp_ec = decode_jwt_payload(rp_ec_jwt)

presentation_definition = rp_ec["metadata"]["wallet_relying_party"]["presentation_definition"]
PresentationDefinition(**presentation_definition)
assert response_uri == rp_ec["metadata"]['wallet_relying_party']["response_uris_supported"][0]
assert response_uri == rp_ec["metadata"]["wallet_relying_party"]["response_uris_supported"][0]
encryption_key = rp_ec["metadata"]["wallet_relying_party"]["jwks"]["keys"][1]

response = {
"state": state,
"nonce": nonce,
"vp_token": vp_token,
"presentation_submission": {
"definition_id": "32f54163-7166-48f1-93d8-ff217bdb0653",
Expand All @@ -192,8 +173,8 @@ def create_authorize_response(vp_token: str, state: str, nonce: str, response_ur
}
}
encrypted_response = JWEHelper(
# RSA (EC is not fully supported todate)
JWK(rp_ec["metadata"]['wallet_relying_party']['jwks']['keys'][1])
# RSA (EC is not fully supported to date)
JWK(encryption_key)
).encrypt(response)
return encrypted_response

Expand Down
Loading
Loading