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 }