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  }