github.com/hyperledger/aries-framework-go@v0.3.2/pkg/doc/verifiable/embedded_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/base64"
    10  	"encoding/json"
    11  	"errors"
    12  	"fmt"
    13  
    14  	"github.com/hyperledger/aries-framework-go/pkg/doc/signature/jsonld"
    15  	"github.com/hyperledger/aries-framework-go/pkg/doc/signature/suite"
    16  	"github.com/hyperledger/aries-framework-go/pkg/doc/signature/suite/bbsblssignature2020"
    17  	"github.com/hyperledger/aries-framework-go/pkg/doc/signature/suite/bbsblssignatureproof2020"
    18  	"github.com/hyperledger/aries-framework-go/pkg/doc/signature/suite/ecdsasecp256k1signature2019"
    19  	"github.com/hyperledger/aries-framework-go/pkg/doc/signature/suite/ed25519signature2018"
    20  	"github.com/hyperledger/aries-framework-go/pkg/doc/signature/suite/ed25519signature2020"
    21  	"github.com/hyperledger/aries-framework-go/pkg/doc/signature/suite/jsonwebsignature2020"
    22  	"github.com/hyperledger/aries-framework-go/pkg/doc/signature/verifier"
    23  )
    24  
    25  const (
    26  	ed25519Signature2018        = "Ed25519Signature2018"
    27  	ed25519Signature2020        = "Ed25519Signature2020"
    28  	jsonWebSignature2020        = "JsonWebSignature2020"
    29  	ecdsaSecp256k1Signature2019 = "EcdsaSecp256k1Signature2019"
    30  	bbsBlsSignature2020         = "BbsBlsSignature2020"
    31  	bbsBlsSignatureProof2020    = "BbsBlsSignatureProof2020"
    32  )
    33  
    34  func getProofType(proofMap map[string]interface{}) (string, error) {
    35  	proofType, ok := proofMap["type"]
    36  	if !ok {
    37  		return "", errors.New("proof type is missing")
    38  	}
    39  
    40  	proofTypeStr := safeStringValue(proofType)
    41  	switch proofTypeStr {
    42  	case ed25519Signature2018, jsonWebSignature2020, ecdsaSecp256k1Signature2019,
    43  		bbsBlsSignature2020, bbsBlsSignatureProof2020, ed25519Signature2020:
    44  		return proofTypeStr, nil
    45  	default:
    46  		return "", fmt.Errorf("unsupported proof type: %s", proofType)
    47  	}
    48  }
    49  
    50  type embeddedProofCheckOpts struct {
    51  	publicKeyFetcher   PublicKeyFetcher
    52  	disabledProofCheck bool
    53  
    54  	ldpSuites []verifier.SignatureSuite
    55  
    56  	jsonldCredentialOpts
    57  }
    58  
    59  func checkEmbeddedProof(docBytes []byte, opts *embeddedProofCheckOpts) error {
    60  	if opts.disabledProofCheck {
    61  		return nil
    62  	}
    63  
    64  	var jsonldDoc map[string]interface{}
    65  
    66  	if err := json.Unmarshal(docBytes, &jsonldDoc); err != nil {
    67  		return fmt.Errorf("embedded proof is not JSON: %w", err)
    68  	}
    69  
    70  	delete(jsonldDoc, "jwt")
    71  
    72  	proofElement, ok := jsonldDoc["proof"]
    73  	if !ok || proofElement == nil {
    74  		// do not make a check if there is no proof defined as proof presence is not mandatory
    75  		return nil
    76  	}
    77  
    78  	proofs, err := getProofs(proofElement)
    79  	if err != nil {
    80  		return fmt.Errorf("check embedded proof: %w", err)
    81  	}
    82  
    83  	ldpSuites, err := getSuites(proofs, opts)
    84  	if err != nil {
    85  		return err
    86  	}
    87  
    88  	if opts.publicKeyFetcher == nil {
    89  		return errors.New("public key fetcher is not defined")
    90  	}
    91  
    92  	if len(opts.externalContext) > 0 {
    93  		// Use external contexts for check of the linked data proofs to enrich JSON-LD context vocabulary.
    94  		jsonldDoc["@context"] = jsonld.AppendExternalContexts(jsonldDoc["@context"], opts.externalContext...)
    95  	}
    96  
    97  	err = checkLinkedDataProof(jsonldDoc, ldpSuites, opts.publicKeyFetcher, &opts.jsonldCredentialOpts)
    98  	if err != nil {
    99  		return fmt.Errorf("check embedded proof: %w", err)
   100  	}
   101  
   102  	return nil
   103  }
   104  
   105  // nolint:gocyclo
   106  func getSuites(proofs []map[string]interface{}, opts *embeddedProofCheckOpts) ([]verifier.SignatureSuite, error) {
   107  	ldpSuites := opts.ldpSuites
   108  
   109  	for i := range proofs {
   110  		t, err := getProofType(proofs[i])
   111  		if err != nil {
   112  			return nil, fmt.Errorf("check embedded proof: %w", err)
   113  		}
   114  
   115  		if len(opts.ldpSuites) == 0 {
   116  			switch t {
   117  			case ed25519Signature2018:
   118  				ldpSuites = append(ldpSuites, ed25519signature2018.New(
   119  					suite.WithVerifier(ed25519signature2018.NewPublicKeyVerifier())))
   120  			case ed25519Signature2020:
   121  				ldpSuites = append(ldpSuites, ed25519signature2020.New(
   122  					suite.WithVerifier(ed25519signature2020.NewPublicKeyVerifier())))
   123  			case jsonWebSignature2020:
   124  				ldpSuites = append(ldpSuites, jsonwebsignature2020.New(
   125  					suite.WithVerifier(jsonwebsignature2020.NewPublicKeyVerifier())))
   126  			case ecdsaSecp256k1Signature2019:
   127  				ldpSuites = append(ldpSuites, ecdsasecp256k1signature2019.New(
   128  					suite.WithVerifier(ecdsasecp256k1signature2019.NewPublicKeyVerifier())))
   129  			case bbsBlsSignature2020:
   130  				ldpSuites = append(ldpSuites, bbsblssignature2020.New(
   131  					suite.WithVerifier(bbsblssignature2020.NewG2PublicKeyVerifier())))
   132  			case bbsBlsSignatureProof2020:
   133  				nonce, err := getNonce(proofs[i])
   134  				if err != nil {
   135  					return nil, err
   136  				}
   137  
   138  				ldpSuites = append(ldpSuites, bbsblssignatureproof2020.New(
   139  					suite.WithVerifier(bbsblssignatureproof2020.NewG2PublicKeyVerifier(nonce))))
   140  			}
   141  		}
   142  	}
   143  
   144  	return ldpSuites, nil
   145  }
   146  
   147  func getNonce(proof map[string]interface{}) ([]byte, error) {
   148  	if nonce, ok := proof["nonce"]; ok {
   149  		n, err := base64.StdEncoding.DecodeString(nonce.(string))
   150  		if err != nil {
   151  			return nil, err
   152  		}
   153  
   154  		return n, nil
   155  	}
   156  
   157  	return []byte{}, nil
   158  }
   159  
   160  func getProofs(proofElement interface{}) ([]map[string]interface{}, error) {
   161  	switch p := proofElement.(type) {
   162  	case map[string]interface{}:
   163  		return []map[string]interface{}{p}, nil
   164  
   165  	case []interface{}:
   166  		proofs := make([]map[string]interface{}, len(p))
   167  
   168  		for i := range p {
   169  			proofMap, ok := p[i].(map[string]interface{})
   170  			if !ok {
   171  				return nil, errors.New("invalid proof type")
   172  			}
   173  
   174  			proofs[i] = proofMap
   175  		}
   176  
   177  		return proofs, nil
   178  	}
   179  
   180  	return nil, errors.New("invalid proof type")
   181  }