github.com/hyperledger/aries-framework-go@v0.3.2/pkg/doc/verifiable/example_presentation_test.go (about) 1 /* 2 Copyright SecureKey Technologies Inc. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package verifiable_test 8 9 import ( 10 "crypto/ed25519" 11 "encoding/json" 12 "errors" 13 "fmt" 14 15 "github.com/hyperledger/aries-framework-go/pkg/doc/signature/jsonld" 16 "github.com/hyperledger/aries-framework-go/pkg/doc/signature/suite" 17 "github.com/hyperledger/aries-framework-go/pkg/doc/signature/suite/ed25519signature2018" 18 "github.com/hyperledger/aries-framework-go/pkg/doc/signature/verifier" 19 "github.com/hyperledger/aries-framework-go/pkg/doc/util" 20 "github.com/hyperledger/aries-framework-go/pkg/doc/util/signature" 21 "github.com/hyperledger/aries-framework-go/pkg/doc/verifiable" 22 "github.com/hyperledger/aries-framework-go/pkg/kms" 23 ) 24 25 // The keys are generated by ed25519.GenerateKey(rand.Reader) 26 // 27 //nolint:gochecknoglobals 28 var ( 29 holderPrivKey = ed25519.PrivateKey{10, 192, 72, 230, 66, 255, 51, 97, 14, 57, 149, 164, 232, 251, 31, 164, 168, 82, 239, 155, 253, 223, 111, 148, 165, 76, 60, 17, 3, 63, 76, 192, 61, 133, 23, 17, 77, 132, 169, 196, 47, 203, 19, 71, 145, 144, 92, 145, 131, 101, 36, 251, 89, 216, 117, 140, 132, 226, 78, 187, 59, 58, 200, 255} 30 holderPubKey = ed25519.PublicKey{61, 133, 23, 17, 77, 132, 169, 196, 47, 203, 19, 71, 145, 144, 92, 145, 131, 101, 36, 251, 89, 216, 117, 140, 132, 226, 78, 187, 59, 58, 200, 255} 31 ) 32 33 func ExamplePresentation_JWTClaims() { 34 // The Holder kept the presentation serialized to JSON in her personal verifiable credential wallet. 35 vpStrFromWallet := ` 36 { 37 "@context": [ 38 "https://www.w3.org/2018/credentials/v1", 39 "https://www.w3.org/2018/credentials/examples/v1" 40 ], 41 "id": "urn:uuid:3978344f-8596-4c3a-a978-8fcaba3903c5", 42 "type": [ 43 "VerifiablePresentation", 44 "UniversityDegreeCredential" 45 ], 46 "verifiableCredential": [ 47 { 48 "@context": [ 49 "https://www.w3.org/2018/credentials/v1", 50 "https://www.w3.org/2018/credentials/examples/v1" 51 ], 52 "credentialSchema": [], 53 "credentialSubject": { 54 "degree": { 55 "type": "BachelorDegree", 56 "university": "MIT" 57 }, 58 "id": "did:example:ebfeb1f712ebc6f1c276e12ec21", 59 "name": "Jayden Doe", 60 "spouse": "did:example:c276e12ec21ebfeb1f712ebc6f1" 61 }, 62 "expirationDate": "2020-01-01T19:23:24Z", 63 "id": "http://example.edu/credentials/1872", 64 "issuanceDate": "2010-01-01T19:23:24Z", 65 "issuer": { 66 "id": "did:example:76e12ec712ebc6f1c221ebfeb1f", 67 "name": "Example University" 68 }, 69 "referenceNumber": 83294847, 70 "type": [ 71 "VerifiableCredential", 72 "UniversityDegreeCredential" 73 ] 74 } 75 ], 76 "holder": "did:example:ebfeb1f712ebc6f1c276e12ec21" 77 } 78 ` 79 80 // The Holder wants to send the presentation to the Verifier in JWS. 81 vp, err := verifiable.ParsePresentation([]byte(vpStrFromWallet), verifiable.WithPresDisabledProofCheck(), 82 verifiable.WithPresJSONLDDocumentLoader(getJSONLDDocumentLoader())) 83 if err != nil { 84 panic(fmt.Errorf("failed to decode VP JSON: %w", err)) 85 } 86 87 aud := []string{"did:example:4a57546973436f6f6c4a4a57573"} 88 89 jwtClaims, err := vp.JWTClaims(aud, true) 90 if err != nil { 91 panic(fmt.Errorf("failed to create JWT claims of VP: %w", err)) 92 } 93 94 signer := signature.GetEd25519Signer(holderPrivKey, holderPubKey) 95 96 jws, err := jwtClaims.MarshalJWS(verifiable.EdDSA, signer, "") 97 if err != nil { 98 panic(fmt.Errorf("failed to sign VP inside JWT: %w", err)) 99 } 100 101 fmt.Println(jws) 102 103 // Output: eyJhbGciOiJFZERTQSIsImtpZCI6IiJ9.eyJhdWQiOiJkaWQ6ZXhhbXBsZTo0YTU3NTQ2OTczNDM2ZjZmNmM0YTRhNTc1NzMiLCJpc3MiOiJkaWQ6ZXhhbXBsZTplYmZlYjFmNzEyZWJjNmYxYzI3NmUxMmVjMjEiLCJqdGkiOiJ1cm46dXVpZDozOTc4MzQ0Zi04NTk2LTRjM2EtYTk3OC04ZmNhYmEzOTAzYzUiLCJ2cCI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSIsImh0dHBzOi8vd3d3LnczLm9yZy8yMDE4L2NyZWRlbnRpYWxzL2V4YW1wbGVzL3YxIl0sInR5cGUiOlsiVmVyaWZpYWJsZVByZXNlbnRhdGlvbiIsIlVuaXZlcnNpdHlEZWdyZWVDcmVkZW50aWFsIl0sInZlcmlmaWFibGVDcmVkZW50aWFsIjpbeyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSIsImh0dHBzOi8vd3d3LnczLm9yZy8yMDE4L2NyZWRlbnRpYWxzL2V4YW1wbGVzL3YxIl0sImNyZWRlbnRpYWxTY2hlbWEiOltdLCJjcmVkZW50aWFsU3ViamVjdCI6eyJkZWdyZWUiOnsidHlwZSI6IkJhY2hlbG9yRGVncmVlIiwidW5pdmVyc2l0eSI6Ik1JVCJ9LCJpZCI6ImRpZDpleGFtcGxlOmViZmViMWY3MTJlYmM2ZjFjMjc2ZTEyZWMyMSIsIm5hbWUiOiJKYXlkZW4gRG9lIiwic3BvdXNlIjoiZGlkOmV4YW1wbGU6YzI3NmUxMmVjMjFlYmZlYjFmNzEyZWJjNmYxIn0sImV4cGlyYXRpb25EYXRlIjoiMjAyMC0wMS0wMVQxOToyMzoyNFoiLCJpZCI6Imh0dHA6Ly9leGFtcGxlLmVkdS9jcmVkZW50aWFscy8xODcyIiwiaXNzdWFuY2VEYXRlIjoiMjAxMC0wMS0wMVQxOToyMzoyNFoiLCJpc3N1ZXIiOnsiaWQiOiJkaWQ6ZXhhbXBsZTo3NmUxMmVjNzEyZWJjNmYxYzIyMWViZmViMWYiLCJuYW1lIjoiRXhhbXBsZSBVbml2ZXJzaXR5In0sInJlZmVyZW5jZU51bWJlciI6ODMyOTQ4NDcsInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJVbml2ZXJzaXR5RGVncmVlQ3JlZGVudGlhbCJdfV19fQ.TFDBa7VYD4dgduu7LlMWZzk20oU-cc3X7S3AKAJJsX6_Jok3lE6v-24tdCNJsc4eMVlBs6a43J3aq5MDIyiIDg 104 } 105 106 func ExamplePresentation() { 107 // A Holder loads the credential from verifiable credential wallet in order to send to Verifier. 108 // She embedded the credential into presentation and sends it to the Verifier in JWS form. 109 vcStrFromWallet := ` 110 { 111 "@context": [ 112 "https://www.w3.org/2018/credentials/v1", 113 "https://www.w3.org/2018/credentials/examples/v1" 114 ], 115 "credentialSubject": { 116 "degree": { 117 "type": "BachelorDegree", 118 "university": "MIT" 119 }, 120 "id": "did:example:ebfeb1f712ebc6f1c276e12ec21", 121 "name": "Jayden Doe", 122 "spouse": "did:example:c276e12ec21ebfeb1f712ebc6f1" 123 }, 124 "expirationDate": "2020-01-01T19:23:24Z", 125 "id": "http://example.edu/credentials/1872", 126 "issuanceDate": "2010-01-01T19:23:24Z", 127 "issuer": { 128 "id": "did:example:76e12ec712ebc6f1c221ebfeb1f", 129 "name": "Example University" 130 }, 131 "referenceNumber": 83294847, 132 "type": [ 133 "VerifiableCredential", 134 "UniversityDegreeCredential" 135 ] 136 } 137 ` 138 139 vc, err := verifiable.ParseCredential([]byte(vcStrFromWallet), 140 verifiable.WithJSONLDDocumentLoader(getJSONLDDocumentLoader())) 141 if err != nil { 142 panic(fmt.Errorf("failed to decode VC JSON: %w", err)) 143 } 144 145 vp, err := verifiable.NewPresentation(verifiable.WithCredentials(vc)) 146 if err != nil { 147 panic(fmt.Errorf("failed to build VP from VC: %w", err)) 148 } 149 150 vp.ID = "urn:uuid:3978344f-8596-4c3a-a978-8fcaba3903c5" 151 vp.Holder = "did:example:ebfeb1f712ebc6f1c276e12ec21" 152 153 aud := []string{"did:example:4a57546973436f6f6c4a4a57573"} 154 155 jwtClaims, err := vp.JWTClaims(aud, true) 156 if err != nil { 157 panic(fmt.Errorf("failed to create JWT claims of VP: %w", err)) 158 } 159 160 signer := signature.GetEd25519Signer(holderPrivKey, holderPubKey) 161 162 jws, err := jwtClaims.MarshalJWS(verifiable.EdDSA, signer, "") 163 if err != nil { 164 panic(fmt.Errorf("failed to sign VP inside JWT: %w", err)) 165 } 166 167 fmt.Println(jws) 168 169 // Output: eyJhbGciOiJFZERTQSIsImtpZCI6IiJ9.eyJhdWQiOiJkaWQ6ZXhhbXBsZTo0YTU3NTQ2OTczNDM2ZjZmNmM0YTRhNTc1NzMiLCJpc3MiOiJkaWQ6ZXhhbXBsZTplYmZlYjFmNzEyZWJjNmYxYzI3NmUxMmVjMjEiLCJqdGkiOiJ1cm46dXVpZDozOTc4MzQ0Zi04NTk2LTRjM2EtYTk3OC04ZmNhYmEzOTAzYzUiLCJ2cCI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSJdLCJ0eXBlIjoiVmVyaWZpYWJsZVByZXNlbnRhdGlvbiIsInZlcmlmaWFibGVDcmVkZW50aWFsIjpbeyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSIsImh0dHBzOi8vd3d3LnczLm9yZy8yMDE4L2NyZWRlbnRpYWxzL2V4YW1wbGVzL3YxIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImRlZ3JlZSI6eyJ0eXBlIjoiQmFjaGVsb3JEZWdyZWUiLCJ1bml2ZXJzaXR5IjoiTUlUIn0sImlkIjoiZGlkOmV4YW1wbGU6ZWJmZWIxZjcxMmViYzZmMWMyNzZlMTJlYzIxIiwibmFtZSI6IkpheWRlbiBEb2UiLCJzcG91c2UiOiJkaWQ6ZXhhbXBsZTpjMjc2ZTEyZWMyMWViZmViMWY3MTJlYmM2ZjEifSwiZXhwaXJhdGlvbkRhdGUiOiIyMDIwLTAxLTAxVDE5OjIzOjI0WiIsImlkIjoiaHR0cDovL2V4YW1wbGUuZWR1L2NyZWRlbnRpYWxzLzE4NzIiLCJpc3N1YW5jZURhdGUiOiIyMDEwLTAxLTAxVDE5OjIzOjI0WiIsImlzc3VlciI6eyJpZCI6ImRpZDpleGFtcGxlOjc2ZTEyZWM3MTJlYmM2ZjFjMjIxZWJmZWIxZiIsIm5hbWUiOiJFeGFtcGxlIFVuaXZlcnNpdHkifSwicmVmZXJlbmNlTnVtYmVyIjo4MzI5NDg0NywidHlwZSI6WyJWZXJpZmlhYmxlQ3JlZGVudGlhbCIsIlVuaXZlcnNpdHlEZWdyZWVDcmVkZW50aWFsIl19XX19.DnhBKUNbFjNE2ROS8z3CYKr1D5YiL4zEcEaaVF62ASHaueU-pImf36ayReWTWMzhde1PJ_z3K8uzPt3QZUudAQ 170 } 171 172 func ExamplePresentation_two() { 173 // Holder wants to send 2 credentials to Verifier. 174 // The first VC is created on fly (or just decoded using ParseCredential). 175 vc := &verifiable.Credential{ 176 Context: []string{ 177 "https://www.w3.org/2018/credentials/v1", 178 "https://www.w3.org/2018/credentials/examples/v1", 179 }, 180 ID: "http://example.edu/credentials/1872", 181 Types: []string{ 182 "VerifiableCredential", 183 "UniversityDegreeCredential", 184 }, 185 Subject: UniversityDegreeSubject{ 186 ID: "did:example:ebfeb1f712ebc6f1c276e12ec21", 187 Name: "Jayden Doe", 188 Spouse: "did:example:c276e12ec21ebfeb1f712ebc6f1", 189 Degree: UniversityDegree{ 190 Type: "BachelorDegree", 191 University: "MIT", 192 }, 193 }, 194 Issuer: verifiable.Issuer{ 195 ID: "did:example:76e12ec712ebc6f1c221ebfeb1f", 196 CustomFields: verifiable.CustomFields{"name": "Example University"}, 197 }, 198 Issued: util.NewTime(issued), 199 Expired: util.NewTime(expired), 200 Schemas: []verifiable.TypedID{}, 201 CustomFields: map[string]interface{}{ 202 "referenceNumber": 83294847, 203 }, 204 } 205 206 vcStr := ` 207 { 208 "@context": [ 209 "https://www.w3.org/2018/credentials/v1", 210 "https://www.w3.org/2018/credentials/examples/v1" 211 ], 212 "id": "http://example.edu/credentials/58473", 213 "type": ["VerifiableCredential", "AlumniCredential"], 214 "issuer": "https://example.edu/issuers/14", 215 "issuanceDate": "2010-01-01T19:23:24Z", 216 "credentialSubject": { 217 "id": "did:example:ebfeb1f712ebc6f1c276e12ec21", 218 "alumniOf": "Example University" 219 }, 220 "proof": { 221 "type": "RsaSignature2018" 222 } 223 } 224 ` 225 226 // The second VC is provided in JWS form (e.g. kept in the wallet in that form). 227 vcJWS := "eyJhbGciOiJFZERTQSIsImtpZCI6IiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1Nzc5MDY2MDQsImlhdCI6MTI2MjM3MzgwNCwiaXNzIjoiZGlkOmV4YW1wbGU6NzZlMTJlYzcxMmViYzZmMWMyMjFlYmZlYjFmIiwianRpIjoiaHR0cDovL2V4YW1wbGUuZWR1L2NyZWRlbnRpYWxzLzE4NzIiLCJuYmYiOjEyNjIzNzM4MDQsInN1YiI6ImRpZDpleGFtcGxlOmViZmViMWY3MTJlYmM2ZjFjMjc2ZTEyZWMyMSIsInZjIjp7IkBjb250ZXh0IjpbImh0dHBzOi8vd3d3LnczLm9yZy8yMDE4L2NyZWRlbnRpYWxzL3YxIiwiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvZXhhbXBsZXMvdjEiXSwiY3JlZGVudGlhbFNjaGVtYSI6W10sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImRlZ3JlZSI6eyJ0eXBlIjoiQmFjaGVsb3JEZWdyZWUiLCJ1bml2ZXJzaXR5IjoiTUlUIn0sImlkIjoiZGlkOmV4YW1wbGU6ZWJmZWIxZjcxMmViYzZmMWMyNzZlMTJlYzIxIiwibmFtZSI6IkpheWRlbiBEb2UiLCJzcG91c2UiOiJkaWQ6ZXhhbXBsZTpjMjc2ZTEyZWMyMWViZmViMWY3MTJlYmM2ZjEifSwiaXNzdWVyIjp7Im5hbWUiOiJFeGFtcGxlIFVuaXZlcnNpdHkifSwidHlwZSI6WyJWZXJpZmlhYmxlQ3JlZGVudGlhbCIsIlVuaXZlcnNpdHlEZWdyZWVDcmVkZW50aWFsIl19fQ.AHn2A2q5DL1heX3_izq_2yrsBDhoZ6BGGKhoRvhfMnMUuuOnBOdekdTg-dfUMJgipXRql_6WzBUIj4wTFehXCw" 228 229 vc2, err := verifiable.ParseCredential([]byte(vcStr), 230 verifiable.WithJSONLDDocumentLoader(getJSONLDDocumentLoader()), 231 verifiable.WithDisabledProofCheck()) 232 if err != nil { 233 panic(fmt.Errorf("failed to decode VC JSON: %w", err)) 234 } 235 236 vp, err := verifiable.NewPresentation(verifiable.WithCredentials(vc), 237 verifiable.WithJWTCredentials(vcJWS), verifiable.WithCredentials(vc2)) 238 if err != nil { 239 panic(fmt.Errorf("failed to set credentials of VP: %w", err)) 240 } 241 242 vp.ID = "urn:uuid:3978344f-8596-4c3a-a978-8fcaba3903c" 243 vp.Holder = "did:example:ebfeb1f712ebc6f1c276e12ec21" 244 245 vpBytes, err := json.MarshalIndent(vp, "", "\t") 246 if err != nil { 247 panic(err) 248 } 249 250 fmt.Print(string(vpBytes)) 251 252 // Output: 253 // { 254 // "@context": [ 255 // "https://www.w3.org/2018/credentials/v1" 256 // ], 257 // "holder": "did:example:ebfeb1f712ebc6f1c276e12ec21", 258 // "id": "urn:uuid:3978344f-8596-4c3a-a978-8fcaba3903c", 259 // "type": "VerifiablePresentation", 260 // "verifiableCredential": [ 261 // { 262 // "@context": [ 263 // "https://www.w3.org/2018/credentials/v1", 264 // "https://www.w3.org/2018/credentials/examples/v1" 265 // ], 266 // "credentialSubject": { 267 // "degree": { 268 // "type": "BachelorDegree", 269 // "university": "MIT" 270 // }, 271 // "id": "did:example:ebfeb1f712ebc6f1c276e12ec21", 272 // "name": "Jayden Doe", 273 // "spouse": "did:example:c276e12ec21ebfeb1f712ebc6f1" 274 // }, 275 // "expirationDate": "2020-01-01T19:23:24Z", 276 // "id": "http://example.edu/credentials/1872", 277 // "issuanceDate": "2010-01-01T19:23:24Z", 278 // "issuer": { 279 // "id": "did:example:76e12ec712ebc6f1c221ebfeb1f", 280 // "name": "Example University" 281 // }, 282 // "referenceNumber": 83294847, 283 // "type": [ 284 // "VerifiableCredential", 285 // "UniversityDegreeCredential" 286 // ] 287 // }, 288 // "eyJhbGciOiJFZERTQSIsImtpZCI6IiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1Nzc5MDY2MDQsImlhdCI6MTI2MjM3MzgwNCwiaXNzIjoiZGlkOmV4YW1wbGU6NzZlMTJlYzcxMmViYzZmMWMyMjFlYmZlYjFmIiwianRpIjoiaHR0cDovL2V4YW1wbGUuZWR1L2NyZWRlbnRpYWxzLzE4NzIiLCJuYmYiOjEyNjIzNzM4MDQsInN1YiI6ImRpZDpleGFtcGxlOmViZmViMWY3MTJlYmM2ZjFjMjc2ZTEyZWMyMSIsInZjIjp7IkBjb250ZXh0IjpbImh0dHBzOi8vd3d3LnczLm9yZy8yMDE4L2NyZWRlbnRpYWxzL3YxIiwiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvZXhhbXBsZXMvdjEiXSwiY3JlZGVudGlhbFNjaGVtYSI6W10sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImRlZ3JlZSI6eyJ0eXBlIjoiQmFjaGVsb3JEZWdyZWUiLCJ1bml2ZXJzaXR5IjoiTUlUIn0sImlkIjoiZGlkOmV4YW1wbGU6ZWJmZWIxZjcxMmViYzZmMWMyNzZlMTJlYzIxIiwibmFtZSI6IkpheWRlbiBEb2UiLCJzcG91c2UiOiJkaWQ6ZXhhbXBsZTpjMjc2ZTEyZWMyMWViZmViMWY3MTJlYmM2ZjEifSwiaXNzdWVyIjp7Im5hbWUiOiJFeGFtcGxlIFVuaXZlcnNpdHkifSwidHlwZSI6WyJWZXJpZmlhYmxlQ3JlZGVudGlhbCIsIlVuaXZlcnNpdHlEZWdyZWVDcmVkZW50aWFsIl19fQ.AHn2A2q5DL1heX3_izq_2yrsBDhoZ6BGGKhoRvhfMnMUuuOnBOdekdTg-dfUMJgipXRql_6WzBUIj4wTFehXCw", 289 // { 290 // "@context": [ 291 // "https://www.w3.org/2018/credentials/v1", 292 // "https://www.w3.org/2018/credentials/examples/v1" 293 // ], 294 // "credentialSubject": { 295 // "alumniOf": "Example University", 296 // "id": "did:example:ebfeb1f712ebc6f1c276e12ec21" 297 // }, 298 // "id": "http://example.edu/credentials/58473", 299 // "issuanceDate": "2010-01-01T19:23:24Z", 300 // "issuer": "https://example.edu/issuers/14", 301 // "proof": { 302 // "type": "RsaSignature2018" 303 // }, 304 // "type": [ 305 // "VerifiableCredential", 306 // "AlumniCredential" 307 // ] 308 // } 309 // ] 310 // } 311 } 312 313 func ExamplePresentation_MarshalJSON() { 314 vc := &verifiable.Credential{ 315 Context: []string{ 316 "https://www.w3.org/2018/credentials/v1", 317 "https://www.w3.org/2018/credentials/examples/v1", 318 }, 319 ID: "http://example.edu/credentials/1872", 320 Types: []string{ 321 "VerifiableCredential", 322 "UniversityDegreeCredential", 323 }, 324 Subject: UniversityDegreeSubject{ 325 ID: "did:example:ebfeb1f712ebc6f1c276e12ec21", 326 Name: "Jayden Doe", 327 Spouse: "did:example:c276e12ec21ebfeb1f712ebc6f1", 328 Degree: UniversityDegree{ 329 Type: "BachelorDegree", 330 University: "MIT", 331 }, 332 }, 333 Issuer: verifiable.Issuer{ 334 ID: "did:example:76e12ec712ebc6f1c221ebfeb1f", 335 CustomFields: verifiable.CustomFields{"name": "Example University"}, 336 }, 337 Issued: util.NewTime(issued), 338 Expired: util.NewTime(expired), 339 Schemas: []verifiable.TypedID{}, 340 CustomFields: map[string]interface{}{ 341 "referenceNumber": 83294847, 342 }, 343 } 344 345 vp, err := verifiable.NewPresentation(verifiable.WithCredentials(vc)) 346 if err != nil { 347 panic(fmt.Errorf("failed to set credentials of VP: %w", err)) 348 } 349 350 vp.ID = "urn:uuid:3978344f-8596-4c3a-a978-8fcaba3903c" 351 vp.Holder = "did:example:ebfeb1f712ebc6f1c276e12ec21" 352 353 // json.MarshalIndent() calls Presentation.MarshalJSON() 354 vpJSON, err := json.MarshalIndent(vp, "", "\t") 355 if err != nil { 356 panic(fmt.Errorf("failed to marshal VP to JSON: %w", err)) 357 } 358 359 fmt.Println(string(vpJSON)) 360 361 // Output: 362 // { 363 // "@context": [ 364 // "https://www.w3.org/2018/credentials/v1" 365 // ], 366 // "holder": "did:example:ebfeb1f712ebc6f1c276e12ec21", 367 // "id": "urn:uuid:3978344f-8596-4c3a-a978-8fcaba3903c", 368 // "type": "VerifiablePresentation", 369 // "verifiableCredential": [ 370 // { 371 // "@context": [ 372 // "https://www.w3.org/2018/credentials/v1", 373 // "https://www.w3.org/2018/credentials/examples/v1" 374 // ], 375 // "credentialSubject": { 376 // "degree": { 377 // "type": "BachelorDegree", 378 // "university": "MIT" 379 // }, 380 // "id": "did:example:ebfeb1f712ebc6f1c276e12ec21", 381 // "name": "Jayden Doe", 382 // "spouse": "did:example:c276e12ec21ebfeb1f712ebc6f1" 383 // }, 384 // "expirationDate": "2020-01-01T19:23:24Z", 385 // "id": "http://example.edu/credentials/1872", 386 // "issuanceDate": "2010-01-01T19:23:24Z", 387 // "issuer": { 388 // "id": "did:example:76e12ec712ebc6f1c221ebfeb1f", 389 // "name": "Example University" 390 // }, 391 // "referenceNumber": 83294847, 392 // "type": [ 393 // "VerifiableCredential", 394 // "UniversityDegreeCredential" 395 // ] 396 // } 397 // ] 398 // } 399 } 400 401 //nolint:gocyclo 402 func ExamplePresentation_MarshalledCredentials() { 403 vc := verifiable.Credential{ 404 Context: []string{ 405 "https://www.w3.org/2018/credentials/v1", 406 "https://www.w3.org/2018/credentials/examples/v1", 407 }, 408 ID: "http://example.edu/credentials/1872", 409 Types: []string{ 410 "VerifiableCredential", 411 "UniversityDegreeCredential", 412 }, 413 Subject: UniversityDegreeSubject{ 414 ID: "did:example:ebfeb1f712ebc6f1c276e12ec21", 415 Name: "Jayden Doe", 416 Spouse: "did:example:c276e12ec21ebfeb1f712ebc6f1", 417 Degree: UniversityDegree{ 418 Type: "BachelorDegree", 419 University: "MIT", 420 }, 421 }, 422 Issuer: verifiable.Issuer{ 423 ID: "did:example:76e12ec712ebc6f1c221ebfeb1f", 424 CustomFields: verifiable.CustomFields{"name": "Example University"}, 425 }, 426 Issued: util.NewTime(issued), 427 Expired: util.NewTime(expired), 428 Schemas: []verifiable.TypedID{}, 429 } 430 431 // Put JWS form of VC into VP. 432 vcJWTClaims, err := vc.JWTClaims(true) 433 if err != nil { 434 panic(fmt.Errorf("failed to set credentials of VP: %w", err)) 435 } 436 437 issuerSigner := signature.GetEd25519Signer(issuerPrivKey, issuerPubKey) 438 439 vcJWS, err := vcJWTClaims.MarshalJWS(verifiable.EdDSA, issuerSigner, "did:123#i-kid") 440 if err != nil { 441 panic(fmt.Errorf("failed to sign VC JWT: %w", err)) 442 } 443 444 vp, err := verifiable.NewPresentation(verifiable.WithJWTCredentials(vcJWS)) 445 if err != nil { 446 panic(fmt.Errorf("failed to set credentials of VP: %w", err)) 447 } 448 449 vp.ID = "urn:uuid:3978344f-8596-4c3a-a978-8fcaba3903c" 450 vp.Holder = "did:example:ebfeb1f712ebc6f1c276e12ec21" 451 452 // Marshal VP to JWS as well. 453 454 vpJWTClaims, err := vp.JWTClaims(nil, true) 455 if err != nil { 456 panic(fmt.Errorf("failed to create JWT claims of VP: %w", err)) 457 } 458 459 holderSigner := signature.GetEd25519Signer(holderPrivKey, holderPubKey) 460 461 vpJWS, err := vpJWTClaims.MarshalJWS(verifiable.EdDSA, holderSigner, "did:123#h-kid") 462 if err != nil { 463 panic(fmt.Errorf("failed to sign VP inside JWT: %w", err)) 464 } 465 466 // Decode VP from JWS. 467 // Note that VC-s inside will be decoded as well. If they are JWS, their signature is verified 468 // and thus we need to make sure the public key fetcher can retrieve the public key. 469 vp, err = verifiable.ParsePresentation( 470 []byte(vpJWS), 471 verifiable.WithPresPublicKeyFetcher(func(issuerID, keyID string) (*verifier.PublicKey, error) { 472 switch keyID { 473 case "i-kid": 474 return &verifier.PublicKey{ 475 Type: kms.ED25519, 476 Value: issuerPubKey, 477 }, nil 478 case "h-kid": 479 return &verifier.PublicKey{ 480 Type: kms.ED25519, 481 Value: holderPubKey, 482 }, nil 483 default: 484 return nil, fmt.Errorf("unexpected key: %s", keyID) 485 } 486 }), verifiable.WithPresJSONLDDocumentLoader(getJSONLDDocumentLoader())) 487 if err != nil { 488 panic(fmt.Errorf("failed to decode VP JWS: %w", err)) 489 } 490 491 // Get credentials in binary form. 492 vpCreds, err := vp.MarshalledCredentials() 493 if err != nil { 494 panic(fmt.Errorf("failed to get marshalled credentials from decoded presentation: %w", err)) 495 } 496 497 if len(vpCreds) != 1 { 498 panic("Expected 1 credential inside presentation") 499 } 500 501 // Decoded credential. 502 vcDecoded, err := verifiable.ParseCredential(vpCreds[0], 503 verifiable.WithDisabledProofCheck(), 504 verifiable.WithJSONLDDocumentLoader(getJSONLDDocumentLoader())) 505 if err != nil { 506 panic(fmt.Errorf("failed to decode VC: %w", err)) 507 } 508 509 vcDecodedJSON, err := json.MarshalIndent(vcDecoded, "", "\t") 510 if err != nil { 511 panic(fmt.Errorf("failed to marshal VP to JSON: %w", err)) 512 } 513 514 fmt.Println(string(vcDecodedJSON)) 515 516 // Output: "eyJhbGciOiJFZERTQSIsImtpZCI6ImRpZDoxMjMjaS1raWQifQ.eyJleHAiOjE1Nzc5MDY2MDQsImlhdCI6MTI2MjM3MzgwNCwiaXNzIjoiZGlkOmV4YW1wbGU6NzZlMTJlYzcxMmViYzZmMWMyMjFlYmZlYjFmIiwianRpIjoiaHR0cDovL2V4YW1wbGUuZWR1L2NyZWRlbnRpYWxzLzE4NzIiLCJuYmYiOjEyNjIzNzM4MDQsInN1YiI6ImRpZDpleGFtcGxlOmViZmViMWY3MTJlYmM2ZjFjMjc2ZTEyZWMyMSIsInZjIjp7IkBjb250ZXh0IjpbImh0dHBzOi8vd3d3LnczLm9yZy8yMDE4L2NyZWRlbnRpYWxzL3YxIiwiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvZXhhbXBsZXMvdjEiXSwiY3JlZGVudGlhbFN1YmplY3QiOnsiZGVncmVlIjp7InR5cGUiOiJCYWNoZWxvckRlZ3JlZSIsInVuaXZlcnNpdHkiOiJNSVQifSwiaWQiOiJkaWQ6ZXhhbXBsZTplYmZlYjFmNzEyZWJjNmYxYzI3NmUxMmVjMjEiLCJuYW1lIjoiSmF5ZGVuIERvZSIsInNwb3VzZSI6ImRpZDpleGFtcGxlOmMyNzZlMTJlYzIxZWJmZWIxZjcxMmViYzZmMSJ9LCJpc3N1ZXIiOnsibmFtZSI6IkV4YW1wbGUgVW5pdmVyc2l0eSJ9LCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIiwiVW5pdmVyc2l0eURlZ3JlZUNyZWRlbnRpYWwiXX19.K7MhsyiuJMWen87MKyjHFEEH_866xXnD3IlY4L-nF3sKsUInZRuqyqU3pORbDCefpIx1fL3HLi2GFSRcXQvEDA" 517 } 518 519 //nolint:gocyclo 520 func ExamplePresentation_AddLinkedDataProof() { 521 // 1. ISSUER issues a VC. 522 vcToIssue := ` 523 { 524 "@context": [ 525 "https://www.w3.org/2018/credentials/v1", 526 "https://www.w3.org/2018/credentials/examples/v1" 527 ], 528 "credentialSubject": { 529 "degree": { 530 "type": "BachelorDegree", 531 "university": "MIT" 532 }, 533 "id": "did:example:ebfeb1f712ebc6f1c276e12ec21", 534 "name": "Jayden Doe", 535 "spouse": "did:example:c276e12ec21ebfeb1f712ebc6f1" 536 }, 537 "expirationDate": "2020-01-01T19:23:24Z", 538 "id": "http://example.edu/credentials/1872", 539 "issuanceDate": "2010-01-01T19:23:24Z", 540 "issuer": { 541 "id": "did:example:76e12ec712ebc6f1c221ebfeb1f", 542 "name": "Example University" 543 }, 544 "type": [ 545 "VerifiableCredential", 546 "UniversityDegreeCredential" 547 ] 548 } 549 ` 550 551 issuedVC, err := verifiable.ParseCredential([]byte(vcToIssue), 552 verifiable.WithJSONLDDocumentLoader(getJSONLDDocumentLoader()), 553 verifiable.WithDisabledProofCheck()) 554 if err != nil { 555 panic(fmt.Errorf("failed to decode VC JSON: %w", err)) 556 } 557 558 issuerSigner := signature.GetEd25519Signer(issuerPrivKey, issuerPubKey) 559 560 err = issuedVC.AddLinkedDataProof(&verifiable.LinkedDataProofContext{ 561 Created: &issued, 562 SignatureType: "Ed25519Signature2018", 563 Suite: ed25519signature2018.New(suite.WithSigner(issuerSigner)), 564 SignatureRepresentation: verifiable.SignatureJWS, 565 VerificationMethod: "did:example:123456#key1", 566 }, jsonld.WithDocumentLoader(getJSONLDDocumentLoader())) 567 if err != nil { 568 panic(fmt.Errorf("failed to add linked data proof: %w", err)) 569 } 570 571 issuedVCBytes, err := issuedVC.MarshalJSON() 572 if err != nil { 573 panic(fmt.Errorf("failed to marshal VC to JSON: %w", err)) 574 } 575 576 // 2. ISSUER creates a VP with the VC enclosed. 577 vcFromHolderWallet, err := verifiable.ParseCredential(issuedVCBytes, 578 verifiable.WithJSONLDDocumentLoader(getJSONLDDocumentLoader()), 579 verifiable.WithDisabledProofCheck()) 580 if err != nil { 581 panic(fmt.Errorf("failed to decode VC JSON: %w", err)) 582 } 583 584 vpToVerify, err := verifiable.NewPresentation(verifiable.WithCredentials(vcFromHolderWallet)) 585 if err != nil { 586 panic(fmt.Errorf("failed to build VP from VC: %w", err)) 587 } 588 589 vpToVerify.Holder = "did:example:ebfeb1f712ebc6f1c276e12ec22" 590 vpToVerify.ID = "urn:uuid:3978344f-8596-4c3a-a978-8fcaba3903c6" 591 592 holderVerifier := signature.GetEd25519Signer(holderPrivKey, holderPubKey) 593 594 err = vpToVerify.AddLinkedDataProof(&verifiable.LinkedDataProofContext{ 595 Created: &issued, 596 SignatureType: "Ed25519Signature2018", 597 Suite: ed25519signature2018.New(suite.WithSigner(holderVerifier)), 598 SignatureRepresentation: verifiable.SignatureJWS, 599 VerificationMethod: "did:example:987654#key1", 600 }, jsonld.WithDocumentLoader(getJSONLDDocumentLoader())) 601 if err != nil { 602 panic(fmt.Errorf("failed to add linked data proof: %w", err)) 603 } 604 605 vpJSONWithProof, err := vpToVerify.MarshalJSON() 606 if err != nil { 607 panic(fmt.Errorf("failed to marshal VP to JSON: %w", err)) 608 } 609 610 // 3. VERIFIER verifies the presentation. 611 ed25519Suite := ed25519signature2018.New(suite.WithVerifier(ed25519signature2018.NewPublicKeyVerifier())) 612 613 vp, err := verifiable.ParsePresentation(vpJSONWithProof, 614 verifiable.WithPresPublicKeyFetcher(func(issuerID, keyID string) (*verifier.PublicKey, error) { 615 // both VP and enclosed VC signatures are verified, so we need to provide key resolving for all 616 switch issuerID { 617 case "did:example:123456": // issuer 618 return &verifier.PublicKey{ 619 Type: "Ed25519Signature2018", 620 Value: issuerPubKey, 621 }, nil 622 623 case "did:example:987654": 624 return &verifier.PublicKey{ 625 Type: "Ed25519Signature2018", 626 Value: holderPubKey, 627 }, nil 628 } 629 630 return nil, errors.New("unsupported issuer") 631 }), 632 verifiable.WithPresEmbeddedSignatureSuites(ed25519Suite), 633 verifiable.WithPresJSONLDDocumentLoader(getJSONLDDocumentLoader())) 634 if err != nil { 635 panic(fmt.Errorf("failed to decode VP JWS: %w", err)) 636 } 637 638 vpJSON, err := json.MarshalIndent(vp, "", "\t") 639 if err != nil { 640 panic(fmt.Errorf("failed to marshal VC to JSON: %w", err)) 641 } 642 643 fmt.Println(string(vpJSON)) 644 645 // Output: { 646 // "@context": [ 647 // "https://www.w3.org/2018/credentials/v1" 648 // ], 649 // "holder": "did:example:ebfeb1f712ebc6f1c276e12ec22", 650 // "id": "urn:uuid:3978344f-8596-4c3a-a978-8fcaba3903c6", 651 // "proof": { 652 // "created": "2010-01-01T19:23:24Z", 653 // "jws": "eyJhbGciOiJFZERTQSIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19..8stDRasAcYjkQiqiczyFJdkff8VJIF3Lbaq5BNTaC-PcvJHGo2Xja8GTsHByTOx7QNCwC3bNiboPgfXtmm8aBA", 654 // "proofPurpose": "assertionMethod", 655 // "type": "Ed25519Signature2018", 656 // "verificationMethod": "did:example:987654#key1" 657 // }, 658 // "type": "VerifiablePresentation", 659 // "verifiableCredential": [ 660 // { 661 // "@context": [ 662 // "https://www.w3.org/2018/credentials/v1", 663 // "https://www.w3.org/2018/credentials/examples/v1" 664 // ], 665 // "credentialSubject": { 666 // "degree": { 667 // "type": "BachelorDegree", 668 // "university": "MIT" 669 // }, 670 // "id": "did:example:ebfeb1f712ebc6f1c276e12ec21", 671 // "name": "Jayden Doe", 672 // "spouse": "did:example:c276e12ec21ebfeb1f712ebc6f1" 673 // }, 674 // "expirationDate": "2020-01-01T19:23:24Z", 675 // "id": "http://example.edu/credentials/1872", 676 // "issuanceDate": "2010-01-01T19:23:24Z", 677 // "issuer": { 678 // "id": "did:example:76e12ec712ebc6f1c221ebfeb1f", 679 // "name": "Example University" 680 // }, 681 // "proof": { 682 // "created": "2010-01-01T19:23:24Z", 683 // "jws": "eyJhbGciOiJFZERTQSIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19..mQCxgQDvAYI-2YYCkHHe-at9eNI_wN03R6CRyjycb3CnfPWezbo6zEGe94W2AdYsBhC_Zzedcn_ZKgccMYFnCQ", 684 // "proofPurpose": "assertionMethod", 685 // "type": "Ed25519Signature2018", 686 // "verificationMethod": "did:example:123456#key1" 687 // }, 688 // "type": [ 689 // "VerifiableCredential", 690 // "UniversityDegreeCredential" 691 // ] 692 // } 693 // ] 694 //} 695 }