2023-10-24 08:19:55 +00:00
|
|
|
import didkit
|
|
|
|
import json
|
2023-11-10 05:45:12 +00:00
|
|
|
import idhub_ssikit
|
2024-02-22 11:09:08 +00:00
|
|
|
import logging
|
|
|
|
from sys import stderr
|
2023-10-24 08:19:55 +00:00
|
|
|
|
2023-11-22 13:09:08 +00:00
|
|
|
|
2024-02-22 11:09:08 +00:00
|
|
|
def test_all_use_cases():
|
2024-01-03 15:53:06 +00:00
|
|
|
vcs = [
|
|
|
|
'membership-card',
|
|
|
|
'financial-vulnerability',
|
|
|
|
'course-credential',
|
|
|
|
'federation-membership',
|
2024-01-25 10:02:41 +00:00
|
|
|
'e-operator-claim'
|
2024-01-03 15:53:06 +00:00
|
|
|
]
|
2024-02-22 11:09:08 +00:00
|
|
|
# Test basic VC issuance: did:key, no revocation checks (they are not supported with did:key)
|
2024-01-03 15:53:06 +00:00
|
|
|
for vc in vcs:
|
2024-02-22 11:09:08 +00:00
|
|
|
print(f"trying {vc} in did:key mode... ", end="", file=stderr)
|
2024-01-03 15:53:06 +00:00
|
|
|
try:
|
2024-02-22 11:09:08 +00:00
|
|
|
signed_cred = issue_vc_test_newstyle(vc, use_web=False)
|
2024-01-03 15:53:06 +00:00
|
|
|
ok, err = idhub_ssikit.verify_credential(signed_cred)
|
|
|
|
if ok:
|
2024-02-22 11:09:08 +00:00
|
|
|
print("OK", file=stderr)
|
2024-01-03 15:53:06 +00:00
|
|
|
else:
|
2024-02-22 11:09:08 +00:00
|
|
|
print("FAILED!", err, file=stderr)
|
2024-01-03 15:53:06 +00:00
|
|
|
except Exception as e:
|
2024-02-22 11:09:08 +00:00
|
|
|
logging.exception("FAILED! With exception:")
|
|
|
|
# Test VC issuance using did:web DIDs for the issuer, unrevoked, and check revocation
|
|
|
|
print("", file=stderr)
|
|
|
|
for vc in vcs:
|
|
|
|
print(f"trying {vc} in did:web mode, unrevoked... ", end="", file=stderr)
|
|
|
|
try:
|
|
|
|
signed_cred = issue_vc_test_newstyle(vc, use_web=True, did_revokes_vc=False)
|
|
|
|
ok, err = idhub_ssikit.verify_credential(signed_cred)
|
|
|
|
if ok:
|
|
|
|
print("OK", file=stderr)
|
|
|
|
else:
|
|
|
|
print("FAILED!", err, file=stderr)
|
|
|
|
except Exception as e:
|
|
|
|
logging.exception("FAILED! With exception:")
|
|
|
|
# Test VC issuance using did:web DIDs for the issuer, *revoked*, and check revocation
|
|
|
|
print("", file=stderr)
|
|
|
|
for vc in vcs:
|
|
|
|
print(f"trying {vc} in did:web mode, *REVOKED*... ", end="", file=stderr)
|
|
|
|
try:
|
|
|
|
signed_cred = issue_vc_test_newstyle(vc, use_web=True, did_revokes_vc=True)
|
|
|
|
ok, err = idhub_ssikit.verify_credential(signed_cred)
|
|
|
|
if not ok:
|
|
|
|
print("OK", file=stderr)
|
|
|
|
else:
|
|
|
|
print("FAILED! Credential ", err, file=stderr)
|
|
|
|
except Exception as e:
|
|
|
|
logging.exception("FAILED! With exception:")
|
|
|
|
# Test VC resistance to tampering by modifying a credential after signature
|
|
|
|
print("", file=stderr)
|
|
|
|
for vc in vcs:
|
|
|
|
print(f"tampering {vc} after issuance, check that it fails to verify... ", end="", file=stderr)
|
|
|
|
try:
|
|
|
|
issue_vc_test_and_fail_verification(vc) # All went well if this doesn't raise an exception
|
|
|
|
print("OK", file=stderr)
|
|
|
|
except Exception as e:
|
|
|
|
logging.exception("FAILED!")
|
|
|
|
# Test VP issuance and signature
|
|
|
|
print("", file=stderr)
|
|
|
|
print(f"doing end-to-end VP test, expected success... ", end="", file=stderr)
|
|
|
|
ok, reason = issue_and_sign_vp_test(revoked_credential=False)
|
|
|
|
assert ok is True
|
|
|
|
print("OK", file=stderr)
|
|
|
|
print(f"doing end-to-end VP test, expected failure... ", end="", file=stderr)
|
|
|
|
ok, reason = issue_and_sign_vp_test(revoked_credential=True)
|
|
|
|
assert ok is False
|
|
|
|
print("OK", file=stderr)
|
|
|
|
|
|
|
|
|
|
|
|
def issue_vc_test_newstyle(vc_name,
|
|
|
|
use_web=True,
|
|
|
|
did_revokes_vc=False,
|
|
|
|
holder_jwk=None):
|
2024-01-25 10:02:41 +00:00
|
|
|
jwk_issuer = '{"kty":"OKP","crv":"Ed25519","x":"piojLFIHQ4Z6heRuPI87nrfMJKdet1dJIPG15iGjmDE","d":"zpOBTDrp_iNQTY5nZlIxLA34Sl7FXWXNGehFktznxTM"}'
|
2024-02-22 11:09:08 +00:00
|
|
|
jwk_subject = holder_jwk or '{"kty":"OKP","crv":"Ed25519","x":"BuKyt44QKYSX6kmAt771ai37lIFNwYlhugWXPiqcyYU","d":"qbvMhSCPKvQ-vSkqNr3q8gWY5zPUj7ry0t2YnmT7agc"}'
|
2024-01-25 10:02:41 +00:00
|
|
|
did_subject = didkit.key_to_did("key", jwk_subject)
|
2024-02-14 14:43:24 +00:00
|
|
|
if use_web:
|
|
|
|
if did_revokes_vc:
|
|
|
|
did_issuer = "did:web:idhub.pangea.org:did-registry:allRevoked"
|
|
|
|
else:
|
|
|
|
did_issuer = "did:web:idhub.pangea.org:did-registry:noneRevoked"
|
|
|
|
else:
|
|
|
|
did_issuer = didkit.key_to_did("key", jwk_issuer)
|
2024-02-01 21:12:50 +00:00
|
|
|
vc_template = json.load(open(f'schemas/vc_templates/{vc_name}.json'))
|
|
|
|
data_base = json.load(open(f'schemas/vc_examples/base--data.json'))
|
|
|
|
data_specific = json.load(open(f'schemas/vc_examples/{vc_name}--data.json'))
|
2024-02-22 11:09:08 +00:00
|
|
|
data = idhub_ssikit.deep_merge_dict(data_base, data_specific)
|
2024-02-14 14:43:24 +00:00
|
|
|
data["issuer"]["id"] = did_issuer
|
|
|
|
data["credentialSubject"]["id"] = did_subject
|
2024-02-22 11:09:08 +00:00
|
|
|
if use_web:
|
|
|
|
data["credentialStatus"]["id"] = did_issuer
|
|
|
|
data["credentialStatus"]["revocationBitmapIndex"] = 42
|
|
|
|
vc_rendered_unsigned = idhub_ssikit.deep_merge_dict(vc_template, data)
|
2024-01-25 10:02:41 +00:00
|
|
|
|
|
|
|
signed_credential = idhub_ssikit.render_and_sign_credential(
|
|
|
|
vc_rendered_unsigned,
|
|
|
|
jwk_issuer,
|
|
|
|
)
|
2024-01-03 15:53:06 +00:00
|
|
|
return signed_credential
|
|
|
|
|
|
|
|
|
|
|
|
def issue_vc_test_and_fail_verification(vc_name):
|
2023-11-28 08:45:06 +00:00
|
|
|
def replace(s, position, character):
|
|
|
|
return s[:position] + character + s[position+1:]
|
2024-02-22 11:09:08 +00:00
|
|
|
|
|
|
|
signed_credential = issue_vc_test_newstyle(vc_name)
|
|
|
|
ok, reason = idhub_ssikit.verify_credential(signed_credential)
|
|
|
|
assert ok is True, (ok, reason)
|
2024-01-03 15:53:06 +00:00
|
|
|
signed_credential = replace(signed_credential, (len(signed_credential)//4)*3, ".")
|
2024-02-22 11:09:08 +00:00
|
|
|
ok, reason = idhub_ssikit.verify_credential(signed_credential)
|
|
|
|
assert ok is False, (ok, reason)
|
2023-11-28 08:45:06 +00:00
|
|
|
|
2023-11-22 13:09:08 +00:00
|
|
|
|
2024-02-22 11:09:08 +00:00
|
|
|
def issue_and_sign_vp_test(revoked_credential=False):
|
2023-11-27 06:26:02 +00:00
|
|
|
"""
|
|
|
|
In this example execution two Verifiable Credentials associated with a single Holder are issued and then
|
|
|
|
combined into a single Verifiable Presentation.
|
|
|
|
The Verifiable Credentials are of two different models. The use-case is meant to mimic
|
|
|
|
- Holder being a physical person,
|
|
|
|
- Issuer A being "Pare Manel" foundation,
|
|
|
|
- Issuer B being "EXO" foundation,
|
|
|
|
- Verifier (not pictured) being "Som Connexio", which wants verifiable data of the Holder from both Issuers.
|
|
|
|
"""
|
2024-02-22 11:09:08 +00:00
|
|
|
holder_jwk = didkit.generate_ed25519_key()
|
|
|
|
holder_did = didkit.key_to_did("key", holder_jwk)
|
|
|
|
vc1 = issue_vc_test_newstyle('membership-card', use_web=True, holder_jwk=holder_jwk)
|
|
|
|
vc2 = issue_vc_test_newstyle('course-credential', use_web=True, did_revokes_vc=revoked_credential, holder_jwk=holder_jwk)
|
|
|
|
signed_presentation = idhub_ssikit.issue_verifiable_presentation(
|
|
|
|
[json.loads(vc1), json.loads(vc2)],
|
|
|
|
holder_jwk,
|
|
|
|
holder_did,
|
|
|
|
"https://idhub.pangea.org/presentations/42"
|
2023-11-22 13:09:08 +00:00
|
|
|
)
|
2024-01-25 10:02:41 +00:00
|
|
|
|
2024-02-22 11:09:08 +00:00
|
|
|
return idhub_ssikit.verify_presentation(signed_presentation)
|