github.com/hyperledger/aries-framework-go@v0.3.2/pkg/doc/sdjwt/holder/example_test.go (about)

     1  /*
     2  Copyright SecureKey Technologies Inc. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package holder
     8  
     9  import (
    10  	"bytes"
    11  	"crypto/ed25519"
    12  	"crypto/rand"
    13  	"encoding/json"
    14  	"fmt"
    15  	"sort"
    16  	"time"
    17  
    18  	"github.com/go-jose/go-jose/v3/jwt"
    19  
    20  	"github.com/hyperledger/aries-framework-go/pkg/doc/jose/jwk"
    21  	"github.com/hyperledger/aries-framework-go/pkg/doc/jose/jwk/jwksupport"
    22  	afjwt "github.com/hyperledger/aries-framework-go/pkg/doc/jwt"
    23  	"github.com/hyperledger/aries-framework-go/pkg/doc/sdjwt/common"
    24  	"github.com/hyperledger/aries-framework-go/pkg/doc/sdjwt/issuer"
    25  )
    26  
    27  func ExampleParse() {
    28  	signer, signatureVerifier, err := setUp()
    29  	if err != nil {
    30  		fmt.Println("failed to set-up test: %w", err.Error())
    31  	}
    32  
    33  	claims := map[string]interface{}{
    34  		"given_name": "Albert",
    35  		"last_name":  "Smith",
    36  	}
    37  
    38  	// Issuer will issue SD-JWT for specified claims. Salt function is only provided to keep example outcome the same.
    39  	token, err := issuer.New(testIssuer, claims, nil, signer,
    40  		issuer.WithSaltFnc(func() (string, error) {
    41  			return "3jqcb67z9wks08zwiK7EyQ", nil
    42  		}))
    43  	if err != nil {
    44  		fmt.Println("failed to issue SD-JWT: %w", err.Error())
    45  	}
    46  
    47  	combinedFormatForIssuance, err := token.Serialize(false)
    48  	if err != nil {
    49  		fmt.Println("failed to issue SD-JWT: %w", err.Error())
    50  	}
    51  
    52  	// Holder will parse combined format for issuance and hold on to that
    53  	// combined format for issuance and the claims that can be selected.
    54  	holderClaims, err := Parse(combinedFormatForIssuance, WithSignatureVerifier(signatureVerifier))
    55  	if err != nil {
    56  		fmt.Println("holder failed to parse SD-JWT: %w", err.Error())
    57  	}
    58  
    59  	// Sort by claim name, keeping original order or equal elements.
    60  	sort.SliceStable(holderClaims, func(i, j int) bool {
    61  		return holderClaims[i].Name < holderClaims[j].Name
    62  	})
    63  
    64  	holderClaimsJSON, err := marshalObj(holderClaims)
    65  	if err != nil {
    66  		fmt.Println("verifier failed to marshal holder claims: %w", err.Error())
    67  	}
    68  
    69  	fmt.Println(holderClaimsJSON)
    70  
    71  	// Output: [
    72  	//	{
    73  	//		"Disclosure": "WyIzanFjYjY3ejl3a3MwOHp3aUs3RXlRIiwiZ2l2ZW5fbmFtZSIsIkFsYmVydCJd",
    74  	//		"Name": "given_name",
    75  	//		"Value": "Albert"
    76  	//	},
    77  	//	{
    78  	//		"Disclosure": "WyIzanFjYjY3ejl3a3MwOHp3aUs3RXlRIiwibGFzdF9uYW1lIiwiU21pdGgiXQ",
    79  	//		"Name": "last_name",
    80  	//		"Value": "Smith"
    81  	//	}
    82  	//]
    83  }
    84  
    85  func ExampleCreatePresentation() {
    86  	signer, signatureVerifier, err := setUp()
    87  	if err != nil {
    88  		fmt.Println("failed to set-up test: %w", err.Error())
    89  	}
    90  
    91  	holderSigner, holderJWK, err := setUpHolderBinding()
    92  	if err != nil {
    93  		fmt.Println("failed to set-up test: %w", err.Error())
    94  	}
    95  
    96  	claims := map[string]interface{}{
    97  		"given_name": "Albert",
    98  		"last_name":  "Smith",
    99  	}
   100  
   101  	// Issuer will issue SD-JWT for specified claims and holder public key.
   102  	token, err := issuer.New(testIssuer, claims, nil, signer,
   103  		issuer.WithHolderPublicKey(holderJWK))
   104  	if err != nil {
   105  		fmt.Println("failed to issue SD-JWT: %w", err.Error())
   106  	}
   107  
   108  	combinedFormatForIssuance, err := token.Serialize(false)
   109  	if err != nil {
   110  		fmt.Println("failed to issue SD-JWT: %w", err.Error())
   111  	}
   112  
   113  	// Holder will parse combined format for issuance and hold on to that
   114  	// combined format for issuance and the claims that can be selected.
   115  	holderClaims, err := Parse(combinedFormatForIssuance, WithSignatureVerifier(signatureVerifier))
   116  	if err != nil {
   117  		fmt.Println("holder failed to parse SD-JWT: %w", err.Error())
   118  	}
   119  
   120  	// The Holder will only select given_name
   121  	selectedDisclosures := getDisclosuresFromClaimNames([]string{"given_name"}, holderClaims)
   122  
   123  	// Holder will disclose only sub-set of claims to verifier and create holder binding for the verifier.
   124  	combinedFormatForPresentation, err := CreatePresentation(combinedFormatForIssuance, selectedDisclosures,
   125  		WithHolderBinding(&BindingInfo{
   126  			Payload: BindingPayload{
   127  				Nonce:    "nonce",
   128  				Audience: "https://test.com/verifier",
   129  				IssuedAt: jwt.NewNumericDate(time.Now()),
   130  			},
   131  			Signer: holderSigner,
   132  		}))
   133  	if err != nil {
   134  		fmt.Println("holder failed to create presentation: %w", err.Error())
   135  	}
   136  
   137  	cfp := common.ParseCombinedFormatForPresentation(combinedFormatForPresentation)
   138  
   139  	fmt.Println(cfp.HolderBinding != "")
   140  
   141  	// Output: true
   142  }
   143  
   144  func setUp() (*afjwt.JoseED25519Signer, *afjwt.JoseEd25519Verifier, error) {
   145  	issuerPublicKey, issuerPrivateKey, err := ed25519.GenerateKey(rand.Reader)
   146  	if err != nil {
   147  		return nil, nil, err
   148  	}
   149  
   150  	signer := afjwt.NewEd25519Signer(issuerPrivateKey)
   151  
   152  	signatureVerifier, err := afjwt.NewEd25519Verifier(issuerPublicKey)
   153  	if err != nil {
   154  		return nil, nil, err
   155  	}
   156  
   157  	return signer, signatureVerifier, nil
   158  }
   159  
   160  func setUpHolderBinding() (*afjwt.JoseED25519Signer, *jwk.JWK, error) {
   161  	holderPublicKey, holderPrivateKey, err := ed25519.GenerateKey(rand.Reader)
   162  	if err != nil {
   163  		return nil, nil, err
   164  	}
   165  
   166  	holderPublicJWK, err := jwksupport.JWKFromKey(holderPublicKey)
   167  	if err != nil {
   168  		return nil, nil, err
   169  	}
   170  
   171  	holderSigner := afjwt.NewEd25519Signer(holderPrivateKey)
   172  
   173  	return holderSigner, holderPublicJWK, nil
   174  }
   175  
   176  func marshalObj(obj interface{}) (string, error) {
   177  	objBytes, err := json.Marshal(obj)
   178  	if err != nil {
   179  		fmt.Println("failed to marshal object: %w", err.Error())
   180  	}
   181  
   182  	return prettyPrint(objBytes)
   183  }
   184  
   185  func prettyPrint(msg []byte) (string, error) {
   186  	var prettyJSON bytes.Buffer
   187  
   188  	err := json.Indent(&prettyJSON, msg, "", "\t")
   189  	if err != nil {
   190  		return "", err
   191  	}
   192  
   193  	return prettyJSON.String(), nil
   194  }
   195  
   196  func getDisclosuresFromClaimNames(selectedClaimNames []string, claims []*Claim) []string {
   197  	var disclosures []string
   198  
   199  	for _, c := range claims {
   200  		if contains(selectedClaimNames, c.Name) {
   201  			disclosures = append(disclosures, c.Disclosure)
   202  		}
   203  	}
   204  
   205  	return disclosures
   206  }
   207  
   208  func contains(values []string, val string) bool {
   209  	for _, v := range values {
   210  		if v == val {
   211  			return true
   212  		}
   213  	}
   214  
   215  	return false
   216  }