github.com/hyperledger/aries-framework-go@v0.3.2/pkg/doc/verifiable/linked_data_proof.go (about) 1 /* 2 Copyright SecureKey Technologies Inc. All Rights Reserved. 3 SPDX-License-Identifier: Apache-2.0 4 */ 5 6 package verifiable 7 8 import ( 9 "encoding/json" 10 "fmt" 11 "strings" 12 "time" 13 14 "github.com/hyperledger/aries-framework-go/component/models/ld/proof" 15 "github.com/hyperledger/aries-framework-go/pkg/doc/signature/jsonld" 16 "github.com/hyperledger/aries-framework-go/pkg/doc/signature/signer" 17 "github.com/hyperledger/aries-framework-go/pkg/doc/signature/verifier" 18 ) 19 20 const ( 21 resolveIDParts = 2 22 ) 23 24 type keyResolverAdapter struct { 25 pubKeyFetcher PublicKeyFetcher 26 } 27 28 func (k *keyResolverAdapter) Resolve(id string) (*verifier.PublicKey, error) { 29 // id will contain didID#keyID 30 idSplit := strings.Split(id, "#") 31 if len(idSplit) != resolveIDParts { 32 return nil, fmt.Errorf("wrong id %s to resolve", idSplit) 33 } 34 // idSplit[0] is didID 35 // idSplit[1] is keyID 36 pubKey, err := k.pubKeyFetcher(idSplit[0], fmt.Sprintf("#%s", idSplit[1])) 37 if err != nil { 38 return nil, err 39 } 40 41 return pubKey, nil 42 } 43 44 // SignatureRepresentation is a signature value holder type (e.g. "proofValue" or "jws"). 45 type SignatureRepresentation int 46 47 const ( 48 // SignatureProofValue uses "proofValue" field in a Proof to put/read a digital signature. 49 SignatureProofValue SignatureRepresentation = iota 50 51 // SignatureJWS uses "jws" field in a Proof as an element for representation of detached JSON Web Signatures. 52 SignatureJWS 53 ) 54 55 // LinkedDataProofContext holds options needed to build a Linked Data Proof. 56 type LinkedDataProofContext struct { 57 SignatureType string // required 58 Suite signer.SignatureSuite // required 59 SignatureRepresentation SignatureRepresentation // required 60 Created *time.Time // optional 61 VerificationMethod string // optional 62 Challenge string // optional 63 Domain string // optional 64 Purpose string // optional 65 // CapabilityChain must be an array. Each element is either a string or an object. 66 CapabilityChain []interface{} 67 } 68 69 func checkLinkedDataProof(jsonldBytes map[string]interface{}, suites []verifier.SignatureSuite, 70 pubKeyFetcher PublicKeyFetcher, jsonldOpts *jsonldCredentialOpts) error { 71 documentVerifier, err := verifier.New(&keyResolverAdapter{pubKeyFetcher}, suites...) 72 if err != nil { 73 return fmt.Errorf("create new signature verifier: %w", err) 74 } 75 76 processorOpts := mapJSONLDProcessorOpts(jsonldOpts) 77 78 err = documentVerifier.VerifyObject(jsonldBytes, processorOpts...) 79 if err != nil { 80 return fmt.Errorf("check linked data proof: %w", err) 81 } 82 83 return nil 84 } 85 86 func mapJSONLDProcessorOpts(jsonldOpts *jsonldCredentialOpts) []jsonld.ProcessorOpts { 87 var processorOpts []jsonld.ProcessorOpts 88 89 if jsonldOpts.jsonldDocumentLoader != nil { 90 processorOpts = append(processorOpts, jsonld.WithDocumentLoader(jsonldOpts.jsonldDocumentLoader)) 91 } 92 93 if jsonldOpts.jsonldOnlyValidRDF { 94 processorOpts = append(processorOpts, jsonld.WithRemoveAllInvalidRDF()) 95 } else { 96 processorOpts = append(processorOpts, jsonld.WithValidateRDF()) 97 } 98 99 return processorOpts 100 } 101 102 type rawProof struct { 103 Proof json.RawMessage `json:"proof,omitempty"` 104 } 105 106 // addLinkedDataProof adds a new proof to the JSON-LD document (VC or VP). It returns a slice 107 // of the proofs which were already present appended with a newly created proof. 108 func addLinkedDataProof(context *LinkedDataProofContext, jsonldBytes []byte, 109 opts ...jsonld.ProcessorOpts) ([]Proof, error) { 110 documentSigner := signer.New(context.Suite) 111 112 vcWithNewProofBytes, err := documentSigner.Sign(mapContext(context), jsonldBytes, opts...) 113 if err != nil { 114 return nil, fmt.Errorf("add linked data proof: %w", err) 115 } 116 117 // Get a proof from json-ld document. 118 var rProof rawProof 119 120 err = json.Unmarshal(vcWithNewProofBytes, &rProof) 121 if err != nil { 122 return nil, err 123 } 124 125 proofs, err := parseProof(rProof.Proof) 126 if err != nil { 127 return nil, err 128 } 129 130 return proofs, nil 131 } 132 133 func mapContext(context *LinkedDataProofContext) *signer.Context { 134 return &signer.Context{ 135 SignatureType: context.SignatureType, 136 SignatureRepresentation: proof.SignatureRepresentation(context.SignatureRepresentation), 137 Created: context.Created, 138 VerificationMethod: context.VerificationMethod, 139 Challenge: context.Challenge, 140 Domain: context.Domain, 141 Purpose: context.Purpose, 142 CapabilityChain: context.CapabilityChain, 143 } 144 }