-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(prism-agent): add support for hierarchical deterministic key wit…
…h seed (#534) * add key derivation * HD key counter * derive keys in create-operation * add random seed * sanity check * add sql migration script * sql schema for did with different key mode * make wallet api compile * make server compile * make tests compile * fix failing tests * maxErrors = 5 * Remove unused file * rand key reuse random seed derivation * [wip] create new did and increment did index * [wip] persist derivation path * fix missing column * make update did state more strict * resolve key for different key management mode * wip * disallow multiple in-flight update * Construct update ops with hd key * hd key timestamp * Read ekuycount from storage * key rotation material * operation handler module * handle DIDUpdate material * make update flow use DIDUpdateMaterial * hd key path table add operation_hash col * insert hd key path method * enable key rotation on managed DID * make walletAPI tests compile * recover failed tests * random seed to make tests pass * wallet seed resolver * fix test compilation * SeedResolver tests * pr cleanup * operation factory tests
- Loading branch information
Showing
27 changed files
with
1,415 additions
and
304 deletions.
There are no files selected for viewing
36 changes: 36 additions & 0 deletions
36
prism-agent/service/server/src/main/resources/sql/agent/V4__did_hd_key.sql
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
CREATE TYPE public.prism_did_key_mode AS ENUM( | ||
'RANDOM', | ||
'HD' | ||
); | ||
|
||
ALTER TABLE public.prism_did_wallet_state | ||
ADD COLUMN "key_mode" PRISM_DID_KEY_MODE, | ||
ADD COLUMN "did_index" INT UNIQUE; | ||
|
||
UPDATE public.prism_did_wallet_state | ||
SET "key_mode" = 'RANDOM' | ||
WHERE "key_mode" IS NULL; | ||
|
||
ALTER TABLE public.prism_did_wallet_state | ||
ALTER COLUMN "key_mode" SET NOT NULL; | ||
|
||
CREATE TYPE public.prism_did_key_usage AS ENUM( | ||
'MASTER', | ||
'ISSUING', | ||
'KEY_AGREEMENT', | ||
'AUTHENTICATION', | ||
'REVOCATION', | ||
'CAPABILITY_INVOCATION', | ||
'CAPABILITY_DELEGATION' | ||
); | ||
|
||
CREATE TABLE public.prism_did_hd_key( | ||
"did" TEXT NOT NULL, | ||
"created_at" TIMESTAMP WITH TIME ZONE NOT NULL, | ||
"key_id" TEXT NOT NULL, | ||
"key_usage" PRISM_DID_KEY_USAGE, | ||
"key_index" INT, | ||
"operation_hash" BYTEA NOT NULL, | ||
UNIQUE ("did", "key_id", "operation_hash"), | ||
CONSTRAINT fk_did FOREIGN KEY ("did") REFERENCES public.prism_did_wallet_state("did") ON DELETE RESTRICT | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
126 changes: 126 additions & 0 deletions
126
...service/wallet-api/src/main/scala/io/iohk/atala/agent/walletapi/model/KeyManagement.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
package io.iohk.atala.agent.walletapi.model | ||
|
||
import io.iohk.atala.castor.core.model.did.VerificationRelationship | ||
import io.iohk.atala.castor.core.model.did.InternalKeyPurpose | ||
import io.iohk.atala.agent.walletapi.crypto.DerivationPath | ||
import io.iohk.atala.agent.walletapi.crypto.ECKeyPair | ||
|
||
enum KeyManagementMode { | ||
case Random extends KeyManagementMode | ||
case HD extends KeyManagementMode | ||
} | ||
|
||
final case class VerificationRelationshipCounter( | ||
authentication: Int, | ||
assertionMethod: Int, | ||
keyAgreement: Int, | ||
capabilityInvocation: Int, | ||
capabilityDelegation: Int, | ||
) { | ||
def next(keyUsage: VerificationRelationship): VerificationRelationshipCounter = { | ||
keyUsage match { | ||
case VerificationRelationship.Authentication => copy(authentication = authentication + 1) | ||
case VerificationRelationship.AssertionMethod => copy(assertionMethod = assertionMethod + 1) | ||
case VerificationRelationship.KeyAgreement => copy(keyAgreement = keyAgreement + 1) | ||
case VerificationRelationship.CapabilityInvocation => copy(capabilityInvocation = capabilityInvocation + 1) | ||
case VerificationRelationship.CapabilityDelegation => copy(capabilityDelegation = capabilityDelegation + 1) | ||
} | ||
} | ||
} | ||
|
||
object VerificationRelationshipCounter { | ||
def zero: VerificationRelationshipCounter = VerificationRelationshipCounter(0, 0, 0, 0, 0) | ||
} | ||
|
||
final case class InternalKeyCounter( | ||
master: Int, | ||
revocation: Int | ||
) { | ||
def next(keyUsage: InternalKeyPurpose): InternalKeyCounter = { | ||
keyUsage match { | ||
case InternalKeyPurpose.Master => copy(master = master + 1) | ||
case InternalKeyPurpose.Revocation => copy(revocation = revocation + 1) | ||
} | ||
} | ||
} | ||
|
||
object InternalKeyCounter { | ||
def zero: InternalKeyCounter = InternalKeyCounter(0, 0) | ||
} | ||
|
||
/** Key counter of a single DID */ | ||
final case class HdKeyIndexCounter( | ||
didIndex: Int, | ||
verificationRelationship: VerificationRelationshipCounter, | ||
internalKey: InternalKeyCounter | ||
) { | ||
def next(keyUsage: VerificationRelationship | InternalKeyPurpose): HdKeyIndexCounter = { | ||
keyUsage match { | ||
case i: VerificationRelationship => copy(verificationRelationship = verificationRelationship.next(i)) | ||
case i: InternalKeyPurpose => copy(internalKey = internalKey.next(i)) | ||
} | ||
} | ||
|
||
def path(keyUsage: VerificationRelationship | InternalKeyPurpose): ManagedDIDHdKeyPath = { | ||
val keyIndex = keyUsage match { | ||
case VerificationRelationship.AssertionMethod => verificationRelationship.assertionMethod | ||
case VerificationRelationship.KeyAgreement => verificationRelationship.keyAgreement | ||
case VerificationRelationship.CapabilityInvocation => verificationRelationship.capabilityInvocation | ||
case VerificationRelationship.CapabilityDelegation => verificationRelationship.capabilityDelegation | ||
case VerificationRelationship.Authentication => verificationRelationship.authentication | ||
case InternalKeyPurpose.Master => internalKey.master | ||
case InternalKeyPurpose.Revocation => internalKey.revocation | ||
} | ||
ManagedDIDHdKeyPath(didIndex, keyUsage, keyIndex) | ||
} | ||
} | ||
|
||
object HdKeyIndexCounter { | ||
def zero(didIndex: Int): HdKeyIndexCounter = | ||
HdKeyIndexCounter(didIndex, VerificationRelationshipCounter.zero, InternalKeyCounter.zero) | ||
} | ||
|
||
final case class ManagedDIDHdKeyPath( | ||
didIndex: Int, | ||
keyUsage: VerificationRelationship | InternalKeyPurpose, | ||
keyIndex: Int | ||
) { | ||
def derivationPath: Seq[DerivationPath] = | ||
Seq( | ||
DerivationPath.Hardened(0x1d), | ||
DerivationPath.Hardened(didIndex), | ||
DerivationPath.Hardened(keyUsageIndex), | ||
DerivationPath.Hardened(keyIndex) | ||
) | ||
|
||
def keyUsageIndex: Int = mapKeyUsageIndex(keyUsage) | ||
|
||
private def mapKeyUsageIndex(keyUsage: VerificationRelationship | InternalKeyPurpose): Int = { | ||
keyUsage match { | ||
case InternalKeyPurpose.Master => 1 | ||
case VerificationRelationship.AssertionMethod => 2 | ||
case VerificationRelationship.KeyAgreement => 3 | ||
case VerificationRelationship.Authentication => 4 | ||
case InternalKeyPurpose.Revocation => 5 | ||
case VerificationRelationship.CapabilityInvocation => 6 | ||
case VerificationRelationship.CapabilityDelegation => 7 | ||
} | ||
} | ||
} | ||
|
||
private[walletapi] final case class CreateDIDRandKey( | ||
keyPairs: Map[String, ECKeyPair], | ||
internalKeyPairs: Map[String, ECKeyPair] | ||
) | ||
|
||
private[walletapi] final case class UpdateDIDRandKey(newKeyPairs: Map[String, ECKeyPair]) | ||
|
||
private[walletapi] final case class CreateDIDHdKey( | ||
keyPaths: Map[String, ManagedDIDHdKeyPath], | ||
internalKeyPaths: Map[String, ManagedDIDHdKeyPath], | ||
) | ||
|
||
private[walletapi] final case class UpdateDIDHdKey( | ||
newKeyPaths: Map[String, ManagedDIDHdKeyPath], | ||
counter: HdKeyIndexCounter | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 0 additions & 2 deletions
2
...-api/src/main/scala/io/iohk/atala/agent/walletapi/model/error/CreateManagedDIDError.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
9 changes: 0 additions & 9 deletions
9
...api/src/main/scala/io/iohk/atala/agent/walletapi/model/error/ManagedDIDServiceError.scala
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.