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: Defined rules for method-specific-id #353

Merged
merged 3 commits into from
Apr 21, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
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
132 changes: 130 additions & 2 deletions tests/e2e/ssi_tests/e2e_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -812,6 +812,7 @@ def caip10_cosmos_support_test():
did_doc_string_2 = generate_did_document(kp, kp_algo, "osmo")
did_doc_string_2_vm = did_doc_string_2["verificationMethod"][0]
did_doc_string_2_vm["id"] = did_doc_string_2_vm["id"] + "new"
did_doc_string_2_vm["controller"] = did_doc_string_1["verificationMethod"][0]["controller"]

did_doc_string_1["verificationMethod"] = [
did_doc_string_1["verificationMethod"][0],
Expand Down Expand Up @@ -998,7 +999,7 @@ def vm_type_test():
print("4. PASS: Registering DID Document with a verification method of type EcdsaSecp256k1VerificationKey2019. Only publicKeyMultibase is passed.")
kp_algo = "secp256k1"
kp = generate_key_pair(algo=kp_algo)
did_doc_string = generate_did_document(kp, kp_algo)
did_doc_string = generate_did_document(kp, kp_algo, is_uuid=True, bech32prefix="")
did_doc_id = did_doc_string["id"]
did_doc_string["verificationMethod"][0]["blockchainAccountId"] = ""
signers = []
Expand Down Expand Up @@ -1092,4 +1093,131 @@ def vm_type_test():
run_blockchain_command(create_tx_cmd, f"Registering DID with Id: {did_doc_id}")

print("--- Test Completed ---\n")


def method_specific_id_test():
print("\n--- Method Specific ID Tests ---\n")

print("1. PASS: Registering a DID Document where the user provides a blockchain address in MSI that they own")

kp_algo = "secp256k1"
kp_alice = generate_key_pair(algo=kp_algo)
signers = []
did_doc_string = generate_did_document(kp_alice, algo=kp_algo)
did_doc_alice = did_doc_string["id"]
did_doc_alice_vm = did_doc_string["verificationMethod"]
signPair_alice = {
"kp": kp_alice,
"verificationMethodId": did_doc_string["verificationMethod"][0]["id"],
"signing_algo": kp_algo
}
signers.append(signPair_alice)
create_tx_cmd = form_did_create_tx_multisig(did_doc_string, signers, DEFAULT_BLOCKCHAIN_ACCOUNT_NAME)
run_blockchain_command(create_tx_cmd, f"Registering Alice's DID with Id: {did_doc_alice}")

print("2. FAIL: Registering a DID Document where the user provides a blockchain address in MSI that they don't own")

kp_algo = "secp256k1"
kp_bob = generate_key_pair(algo=kp_algo)
signers = []
did_doc_string = generate_did_document(kp_bob, algo=kp_algo)
did_doc_string["controller"] = [did_doc_alice]
did_doc_string["verificationMethod"] = did_doc_alice_vm

did_doc_bob = did_doc_string["id"]
signers.append(signPair_alice)
create_tx_cmd = form_did_create_tx_multisig(did_doc_string, signers, DEFAULT_BLOCKCHAIN_ACCOUNT_NAME)
run_blockchain_command(create_tx_cmd, f"Registering Bob's DID with Id: {did_doc_bob}", True)

print("3. PASS: Registering a DID Document where the user provides a multibase encoded public key in MSI that they own")

kp_algo = "ed25519"
kp_alice = generate_key_pair(algo=kp_algo)
signers = []
did_doc_string = generate_did_document(kp_alice, algo=kp_algo)
did_doc_alice = did_doc_string["id"]
did_doc_alice_vm = did_doc_string["verificationMethod"]
signPair_alice = {
"kp": kp_alice,
"verificationMethodId": did_doc_string["verificationMethod"][0]["id"],
"signing_algo": kp_algo
}
signers.append(signPair_alice)
create_tx_cmd = form_did_create_tx_multisig(did_doc_string, signers, DEFAULT_BLOCKCHAIN_ACCOUNT_NAME)
run_blockchain_command(create_tx_cmd, f"Registering Alice's DID with Id: {did_doc_alice}")

print("4. PASS: Registering a DID Document where the user provides a multibase encoded public key in MSI that they don't own")

kp_algo = "ed25519"
kp_bob = generate_key_pair(algo=kp_algo)
signers = []
did_doc_string = generate_did_document(kp_bob, algo=kp_algo)
did_doc_string["controller"] = [did_doc_alice]
did_doc_string["verificationMethod"] = did_doc_alice_vm

did_doc_bob = did_doc_string["id"]
signers.append(signPair_alice)
create_tx_cmd = form_did_create_tx_multisig(did_doc_string, signers, DEFAULT_BLOCKCHAIN_ACCOUNT_NAME)
run_blockchain_command(create_tx_cmd, f"Registering Bob's DID with Id: {did_doc_bob}")

print("5. FAIL: Attempt to Register Invalid DID Documents with invalid DID Id")

did_id_list = [
"did:hid:1:",
"did:hid:1",
"did:hid:devnet",
"did:hid:devnet:",
"did:hid:devnet:zHiii",
"did:hid:devnet:asa54qf",
"did:hid:devnet:asa54qf|sds",
"did:hid:devnet:-asa54-qfsds",
"did:hid:devnet:.com",
]

for did_id in did_id_list:
did_doc_string["id"] = did_id
create_tx_cmd = form_did_create_tx_multisig(did_doc_string, signers, DEFAULT_BLOCKCHAIN_ACCOUNT_NAME)
run_blockchain_command(create_tx_cmd, f"Registering Invalid DID with Id: {did_id}", True, True)

print("6. PASS: Alice tries to update their DID Document by removing the Verification Method associated with the method specific id (CAIP-10 Blockchain Address)")

kp_algo = "secp256k1"
kp_alice = generate_key_pair(algo=kp_algo)
signers = []
did_doc_string = generate_did_document(kp_alice, algo=kp_algo)
did_doc_alice = did_doc_string["id"]
did_doc_alice_vm = did_doc_string["verificationMethod"]
signPair_alice = {
"kp": kp_alice,
"verificationMethodId": did_doc_string["verificationMethod"][0]["id"],
"signing_algo": kp_algo
}
signers.append(signPair_alice)
create_tx_cmd = form_did_create_tx_multisig(did_doc_string, signers, DEFAULT_BLOCKCHAIN_ACCOUNT_NAME)
run_blockchain_command(create_tx_cmd, f"Registering Alice's DID with Id: {did_doc_alice}")

did_doc_string["verificationMethod"] = []
update_tx_cmd = form_did_update_tx_multisig(did_doc_string, signers, DEFAULT_BLOCKCHAIN_ACCOUNT_NAME)
run_blockchain_command(update_tx_cmd, f"Removal of Verification Method associated with method specific id")

print("7. PASS: Alice tries to update their DID Document by removing the Verification Method associated with the method specific id (Multibase Encoded PublicKey)")

kp_algo = "ed25519"
kp_alice = generate_key_pair(algo=kp_algo)
signers = []
did_doc_string = generate_did_document(kp_alice, algo=kp_algo)
did_doc_alice = did_doc_string["id"]
did_doc_alice_vm = did_doc_string["verificationMethod"]
signPair_alice = {
"kp": kp_alice,
"verificationMethodId": did_doc_string["verificationMethod"][0]["id"],
"signing_algo": kp_algo
}
signers.append(signPair_alice)
create_tx_cmd = form_did_create_tx_multisig(did_doc_string, signers, DEFAULT_BLOCKCHAIN_ACCOUNT_NAME)
run_blockchain_command(create_tx_cmd, f"Registering Alice's DID with Id: {did_doc_alice}")

did_doc_string["verificationMethod"] = []
update_tx_cmd = form_did_update_tx_multisig(did_doc_string, signers, DEFAULT_BLOCKCHAIN_ACCOUNT_NAME)
run_blockchain_command(update_tx_cmd, f"Removal of Verification Method associated with method specific id")

print("--- Test Completed ---\n")
19 changes: 13 additions & 6 deletions tests/e2e/ssi_tests/generate_doc.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from utils import run_command, generate_document_id, get_document_signature, \
secp256k1_pubkey_to_address

def generate_did_document(key_pair, algo="ed25519", bech32prefix="hid"):
def generate_did_document(key_pair, algo="ed25519", bech32prefix="hid", is_uuid=False):
base_document = {
"context" : [
"https://www.w3.org/ns/did/v1"
Expand All @@ -17,7 +17,7 @@ def generate_did_document(key_pair, algo="ed25519", bech32prefix="hid"):
"authentication": [],
}

did_id = generate_document_id("did", key_pair, algo)
did_id = generate_document_id("did", key_pair, algo, is_uuid)

# Form the DID Document
vm_type = ""
Expand All @@ -31,29 +31,36 @@ def generate_did_document(key_pair, algo="ed25519", bech32prefix="hid"):
raise Exception("unknown signing algorithm: " + key_pair)

verification_method = {
"id": did_id + "#key-1",
"type": vm_type,
"controller": did_id,
"id": "",
"type": "",
"controller": "",
"blockchainAccountId": "",
"publicKeyMultibase": ""
}

if algo == "recover-eth":
verification_method["blockchainAccountId"] = "eip155:1:" + key_pair["ethereum_address"]
elif algo == "secp256k1":

if bech32prefix == "hid":
verification_method["blockchainAccountId"] = "cosmos:jagrat:" + \
secp256k1_pubkey_to_address(key_pair["pub_key_base_64"], bech32prefix)
did_id = "did:hid:devnet:" + verification_method["blockchainAccountId"]
elif bech32prefix == "osmo":
verification_method["blockchainAccountId"] = "cosmos:osmosis-1:" + \
secp256k1_pubkey_to_address(key_pair["pub_key_base_64"], bech32prefix)
did_id = "did:hid:devnet:" + verification_method["blockchainAccountId"]
else:
raise Exception("unsupported bech32 prefix " + bech32prefix)
verification_method["blockchainAccountId"] = ""

verification_method["publicKeyMultibase"] = key_pair["pub_key_multibase"]
else:
verification_method["publicKeyMultibase"] = key_pair["pub_key_multibase"]

verification_method["controller"] = did_id
verification_method["type"] = vm_type
verification_method["id"] = did_id + "#k1"

base_document["id"] = did_id
base_document["controller"] = [did_id]
base_document["verificationMethod"] = [verification_method]
Expand Down
1 change: 1 addition & 0 deletions tests/e2e/ssi_tests/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ def run_all_tests():
caip10_ethereum_support_test()
caip10_cosmos_support_test()
vm_type_test()
method_specific_id_test()

print("============= 😃️ All test cases completed successfully ============== \n")

Expand Down
14 changes: 9 additions & 5 deletions tests/e2e/ssi_tests/utils.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import subprocess
import json
import uuid

def run_command(cmd_string):
if type(cmd_string) != str:
Expand Down Expand Up @@ -58,16 +59,19 @@ def generate_key_pair(algo="ed25519"):
kp = json.loads(result_str)
return kp

def generate_document_id(doc_type: str, kp: dict = None, algo: str = "ed25519"):
def generate_document_id(doc_type: str, kp: dict = None, algo: str = "ed25519", is_uuid: bool =False):
id = ""
if not kp:
kp = generate_key_pair(algo)

if algo in ["recover-eth"]:
method_specific_id = kp["ethereum_address"]
if is_uuid:
method_specific_id = str(uuid.uuid4())
else:
method_specific_id = kp["pub_key_multibase"]

if algo in ["recover-eth"]:
method_specific_id = kp["ethereum_address"]
else:
method_specific_id = kp["pub_key_multibase"]

if method_specific_id == None:
raise Exception("Public key is empty")

Expand Down
39 changes: 38 additions & 1 deletion x/ssi/keeper/msg_server_create_did.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,13 @@ func (k msgServer) CreateDID(goCtx context.Context, msg *types.MsgCreateDID) (*t
}

// Validate namespace in DID Document
if err := didDocNamespaceValidation(k, ctx, msgDidDocument); err != nil {
chainNamespace := k.GetChainNamespace(&ctx)
if err := types.DidChainNamespaceValidation(msgDidDocument, chainNamespace); err != nil {
return nil, sdkerrors.Wrap(types.ErrInvalidDidDoc, err.Error())
}

// Validate ownership of method specific id
if err := checkMethodSpecificIdOwnership(msgDidDocument.VerificationMethod, msgDidDocument.Id); err != nil {
return nil, sdkerrors.Wrap(types.ErrInvalidDidDoc, err.Error())
}

Expand Down Expand Up @@ -76,6 +82,37 @@ func (k msgServer) CreateDID(goCtx context.Context, msg *types.MsgCreateDID) (*t
return &types.MsgCreateDIDResponse{Id: id}, nil
}

// checkMethodSpecificIdOwnership validates the ownership of blockchain account id passed in the method specific
// identifier of DID Document. This ensures that a DID ID (containing a blockchain address) is being created by someone
// who owns the blockchain address.
func checkMethodSpecificIdOwnership(verificationMethods []*types.VerificationMethod, didId string) error {
inputMSI, inputMSIType, err := types.GetMethodSpecificIdAndType(didId)
if err != nil {
return err
}

if inputMSIType == types.MSIBlockchainAccountId {
foundMSIinAnyVM := false
for _, vm := range verificationMethods {
if vm.BlockchainAccountId == inputMSI {
foundMSIinAnyVM = true
break
}
}

if !foundMSIinAnyVM {
return fmt.Errorf(
"proof of ownership for method-specific-id in %v must be provided",
didId,
)
} else {
return nil
}
} else {
return nil
}
}

// getControllersForCreateDID returns a list of controller DIDs
// from controller and verification method attributes
func getControllersForCreateDID(didDocument *types.Did) []string {
Expand Down
3 changes: 2 additions & 1 deletion x/ssi/keeper/msg_server_update_did.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ func (k msgServer) UpdateDID(goCtx context.Context, msg *types.MsgUpdateDID) (*t
}

// Validate namespace in DID Document
if err := didDocNamespaceValidation(k, ctx, msgDidDocument); err != nil {
chainNamespace := k.GetChainNamespace(&ctx)
if err := types.DidChainNamespaceValidation(msgDidDocument, chainNamespace); err != nil {
return nil, sdkerrors.Wrap(types.ErrInvalidDidDoc, err.Error())
}

Expand Down
79 changes: 0 additions & 79 deletions x/ssi/keeper/namespace.go

This file was deleted.

Loading