Skip to content

Commit

Permalink
ProofLD Documents
Browse files Browse the repository at this point in the history
Replace the now deprecated SignatureLD documents for the new ProofLD
specification. The 'sign' and 'verify' CLI commands now generate and
verify proof documents.
  • Loading branch information
bcessa committed Sep 10, 2020
1 parent 643c7de commit b2a8ce5
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 56 deletions.
29 changes: 13 additions & 16 deletions agent/storage/mongo.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func (ir *identifierRecord) decode() (*did.Identifier, *did.ProofLD, error) {
return id, proof, nil
}

func (ir *identifierRecord) load(id *did.Identifier, proof *did.ProofLD) {
func (ir *identifierRecord) encode(id *did.Identifier, proof *did.ProofLD) {
data, _ := json.Marshal(id.Document(true))
pp, _ := json.Marshal(proof)
ir.Method = id.Method()
Expand Down Expand Up @@ -97,10 +97,7 @@ func (ms *MongoStore) Close() error {
// Exists returns true if the provided DID instance is already available
// in the store.
func (ms *MongoStore) Exists(id *did.Identifier) bool {
filter := orm.Filter()
filter["method"] = id.Method()
filter["subject"] = id.Subject()
n, _ := ms.did.Count(filter)
n, _ := ms.did.Count(filter(id))
return n > 0
}

Expand All @@ -121,28 +118,28 @@ func (ms *MongoStore) Get(req *protov1.QueryRequest) (*did.Identifier, *did.Proo

// Save will create or update an entry for the provided DID instance.
func (ms *MongoStore) Save(id *did.Identifier, proof *did.ProofLD) error {
// Filter
filter := orm.Filter()
filter["method"] = id.Method()
filter["subject"] = id.Subject()

// Record
rec := new(identifierRecord)
rec.load(id, proof)
rec.encode(id, proof)

// Run upsert operation
return ms.did.Update(filter, rec, true)
return ms.did.Update(filter(id), rec, true)
}

// Delete any existing record for the provided DID instance.
func (ms *MongoStore) Delete(id *did.Identifier) error {
filter := orm.Filter()
filter["method"] = id.Method()
filter["subject"] = id.Subject()
return ms.did.Delete(filter)
return ms.did.Delete(filter(id))
}

// Description returns a brief summary for the storage instance.
func (ms *MongoStore) Description() string {
return "MongoDB data store"
}

// Helper method to produce a selector from a DID instance.
func filter(id *did.Identifier) map[string]interface{} {
filter := orm.Filter()
filter["method"] = id.Method()
filter["subject"] = id.Subject()
return filter
}
54 changes: 32 additions & 22 deletions client/cli/cmd/sign.go → client/cli/cmd/proof.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,50 +11,58 @@ import (
"go.bryk.io/x/cli"
)

var signCmd = &cobra.Command{
Use: "sign",
Short: "Produce a linked digital signature",
Example: "didctl sign [DID reference name] --input \"contents to sign\"",
RunE: runSignCmd,
var proofCmd = &cobra.Command{
Use: "proof",
Short: "Produce a linked digital proof document",
Example: "didctl proof [DID reference name] --input \"contents to sign\"",
Aliases: []string{"sign"},
RunE: runProofCmd,
}

func init() {
params := []cli.Param{
{
Name: "input",
Usage: "contents to sign, if longer than 32 bytes a SHA3-256 will be generated",
FlagKey: "sign.input",
Usage: "contents to sign",
FlagKey: "proof.input",
ByDefault: "",
Short: "i",
},
{
Name: "key",
Usage: "key to use to produce the signature",
FlagKey: "sign.key",
Usage: "key to use to produce the proof",
FlagKey: "proof.key",
ByDefault: "master",
Short: "k",
},
{
Name: "domain",
Usage: "domain value to use when producing LD signatures",
FlagKey: "sign.domain",
Usage: "domain value to use",
FlagKey: "proof.domain",
ByDefault: didDomainValue,
Short: "d",
},
{
Name: "purpose",
Usage: "specific intent for the proof",
FlagKey: "proof.purpose",
ByDefault: "authentication",
Short: "p",
},
}
if err := cli.SetupCommandParams(signCmd, params); err != nil {
if err := cli.SetupCommandParams(proofCmd, params); err != nil {
panic(err)
}
rootCmd.AddCommand(signCmd)
rootCmd.AddCommand(proofCmd)
}

func runSignCmd(_ *cobra.Command, args []string) error {
func runProofCmd(_ *cobra.Command, args []string) error {
if len(args) != 1 {
return errors.New("you must specify a DID reference name")
}

// Get input, CLI takes precedence, from standard input otherwise
input := []byte(viper.GetString("sign.input"))
input := []byte(viper.GetString("proof.input"))
if len(input) == 0 {
input, _ = cli.ReadPipedInput(maxPipeInputSize)
}
Expand All @@ -76,19 +84,21 @@ func runSignCmd(_ *cobra.Command, args []string) error {
}

// Get key
key := id.Key(viper.GetString("sign.key"))
key := id.Key(viper.GetString("proof.key"))
if key == nil {
return fmt.Errorf("selected key is not available on the DID: %s", viper.GetString("sign.key"))
return fmt.Errorf("selected key is not available on the DID: %s", viper.GetString("proof.key"))
}

// Sign
sld, err := key.ProduceSignatureLD(input, viper.GetString("sign.domain"))
// Produce proof
purpose := viper.GetString("proof.purpose")
domain := viper.GetString("proof.domain")
pld, err := key.ProduceProof(input, purpose, domain)
if err != nil {
return fmt.Errorf("failed to produce signature: %s", err)
return fmt.Errorf("failed to produce proof: %s", err)
}
js, err := json.MarshalIndent(sld, "", " ")
js, err := json.MarshalIndent(pld, "", " ")
if err != nil {
return fmt.Errorf("failed to produce signature: %s", err)
return fmt.Errorf("failed to produce proof: %s", err)
}
fmt.Printf("%s\n", js)
return nil
Expand Down
48 changes: 30 additions & 18 deletions client/cli/cmd/verify.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ import (

var verifyCmd = &cobra.Command{
Use: "verify",
Short: "Check the validity of a SignatureLD document",
Example: "didctl verify [signature file] --input \"contents to verify\"",
Short: "Check the validity of a ProofLD document",
Example: "didctl verify [proof file] --input \"contents to verify\"",
RunE: runVerifyCmd,
}

Expand Down Expand Up @@ -49,50 +49,62 @@ func runVerifyCmd(_ *cobra.Command, args []string) error {
return errors.New("no input passed in to verify")
}

// Load signature file
log.Info("verifying LD signature")
// Load proof file
log.Info("verifying proof document")
log.Debug("load signature file")
entry, err := ioutil.ReadFile(args[0])
if err != nil {
return fmt.Errorf("failed to read the signature file: %s", err)
}
log.Debug("decoding contents")
sig := &did.SignatureLD{}
if err = json.Unmarshal(entry, sig); err != nil {
proof := &did.ProofLD{}
if err = json.Unmarshal(entry, proof); err != nil {
return fmt.Errorf("invalid signature file: %s", err)
}

// Validate signature creator
log.Debug("validating signature creator")
id, err := did.Parse(sig.Creator)
// Validate verification method
log.Debug("validating proof verification method")
vm := proof.VerificationMethod
id, err := did.Parse(vm)
if err != nil {
return fmt.Errorf("invalid signature creator: %s", err)
return fmt.Errorf("invalid proof verification method: %s", err)
}

// Retrieve subject
jsDoc, err := resolve(id.String())
if err != nil {
return err
}
doc := &did.Document{}
if err := json.Unmarshal(jsDoc, doc); err != nil {
return err

// Decode result obtained from resolve
doc := new(did.Document)
result := map[string]json.RawMessage{}
if err := json.Unmarshal([]byte(jsDoc), &result); err != nil {
return fmt.Errorf("invalid DID document received: %s", jsDoc)
}
if _, ok := result["document"]; !ok {
return fmt.Errorf("invalid DID document received: %s", jsDoc)
}
if err := json.Unmarshal(result["document"], doc); err != nil {
return fmt.Errorf("invalid DID document received: %s", jsDoc)
}

// Restore peer DID instance
peer, err := did.FromDocument(doc)
if err != nil {
return err
}

// Get creator's key
ck := peer.Key(sig.Creator)
ck := peer.Key(vm)
if ck == nil {
return fmt.Errorf("creator key is not available on the DID Document: %s", sig.Creator)
return fmt.Errorf("verification method is not available on the DID document: %s", vm)
}

// Verify signature
if !ck.VerifySignatureLD(input, sig) {
return errors.New("signature is invalid")
if !ck.VerifyProof(input, proof) {
return errors.New("proof is invalid")
}
log.Info("signature is valid")
log.Info("proof is valid")
return nil
}

0 comments on commit b2a8ce5

Please sign in to comment.