github.com/hyperledger/aries-framework-go@v0.3.2/pkg/doc/verifiable/presentation_jwt_proof_test.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 "crypto/ed25519" 10 "crypto/rand" 11 "errors" 12 "fmt" 13 "testing" 14 "time" 15 16 "github.com/stretchr/testify/require" 17 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/kms" 21 ) 22 23 func TestParsePresentationFromJWS(t *testing.T) { 24 vpBytes := []byte(validPresentation) 25 26 holderSigner, err := newCryptoSigner(kms.RSARS256Type) 27 require.NoError(t, err) 28 29 keyFetcher := createPresKeyFetcher(holderSigner.PublicKeyBytes()) 30 31 t.Run("Decoding presentation from JWS", func(t *testing.T) { 32 jws := createPresJWS(t, vpBytes, false, holderSigner) 33 vpFromJWT, err := newTestPresentation(t, jws, WithPresPublicKeyFetcher(keyFetcher)) 34 require.NoError(t, err) 35 36 vp, err := newTestPresentation(t, vpBytes) 37 require.NoError(t, err) 38 39 // Validate the JWT field, then clear it to validate against the original presentation. 40 require.Equal(t, string(jws), vpFromJWT.JWT) 41 vpFromJWT.JWT = "" 42 43 require.Equal(t, vp, vpFromJWT) 44 }) 45 46 t.Run("Decoding presentation from JWS with minimized fields of \"vp\" claim", func(t *testing.T) { 47 jws := createPresJWS(t, vpBytes, true, holderSigner) 48 vpFromJWT, err := newTestPresentation(t, jws, WithPresPublicKeyFetcher(keyFetcher)) 49 require.NoError(t, err) 50 51 vp, err := newTestPresentation(t, vpBytes) 52 require.NoError(t, err) 53 54 require.Equal(t, string(jws), vpFromJWT.JWT) 55 vpFromJWT.JWT = "" 56 57 require.Equal(t, vp, vpFromJWT) 58 }) 59 60 t.Run("Failed JWT signature verification of presentation", func(t *testing.T) { 61 jws := createPresJWS(t, vpBytes, true, holderSigner) 62 vp, err := newTestPresentation(t, 63 jws, 64 // passing issuers's key, while expecting holder's one 65 WithPresPublicKeyFetcher(func(issuerID, keyID string) (*verifier.PublicKey, error) { 66 issuerSigner, err := newCryptoSigner(kms.RSARS256Type) 67 require.NoError(t, err) 68 69 return &verifier.PublicKey{ 70 Type: kms.RSARS256, 71 Value: issuerSigner.PublicKeyBytes(), 72 }, nil 73 })) 74 75 require.Error(t, err) 76 require.Contains(t, err.Error(), "decoding of Verifiable Presentation from JWS") 77 require.Nil(t, vp) 78 }) 79 80 t.Run("Failed public key fetching", func(t *testing.T) { 81 jws := createPresJWS(t, vpBytes, true, holderSigner) 82 vp, err := newTestPresentation(t, 83 jws, 84 WithPresPublicKeyFetcher(func(issuerID, keyID string) (*verifier.PublicKey, error) { 85 return nil, errors.New("test: public key is not found") 86 })) 87 88 require.Error(t, err) 89 require.Contains(t, err.Error(), "test: public key is not found") 90 require.Nil(t, vp) 91 }) 92 93 t.Run("Not defined public key fetcher", func(t *testing.T) { 94 vp, err := newTestPresentation(t, createPresJWS(t, vpBytes, true, holderSigner)) 95 96 require.Error(t, err) 97 require.Contains(t, err.Error(), "public key fetcher is not defined") 98 require.Nil(t, vp) 99 }) 100 } 101 102 func TestParsePresentationFromJWS_EdDSA(t *testing.T) { 103 vpBytes := []byte(validPresentation) 104 105 signer, err := newCryptoSigner(kms.ED25519Type) 106 require.NoError(t, err) 107 108 vp, err := newTestPresentation(t, vpBytes) 109 require.NoError(t, err) 110 111 // marshal presentation into JWS using EdDSA (Ed25519 signature algorithm). 112 jwtClaims, err := vp.JWTClaims([]string{}, false) 113 require.NoError(t, err) 114 115 vpJWSStr, err := jwtClaims.MarshalJWS(EdDSA, signer, vp.Holder+"#keys-"+keyID) 116 require.NoError(t, err) 117 118 // unmarshal presentation from JWS 119 vpFromJWS, err := newTestPresentation(t, 120 []byte(vpJWSStr), 121 WithPresPublicKeyFetcher(SingleKey(signer.PublicKeyBytes(), kms.ED25519))) 122 require.NoError(t, err) 123 124 require.Equal(t, vpJWSStr, vpFromJWS.JWT) 125 vpFromJWS.JWT = "" 126 127 // unmarshalled presentation must be the same as original one 128 require.Equal(t, vp, vpFromJWS) 129 } 130 131 func TestParsePresentationFromUnsecuredJWT(t *testing.T) { 132 vpBytes := []byte(validPresentation) 133 134 t.Run("Decoding presentation from unsecured JWT", func(t *testing.T) { 135 vpFromJWT, err := newTestPresentation(t, createPresUnsecuredJWT(t, vpBytes, false)) 136 137 require.NoError(t, err) 138 139 vp, err := newTestPresentation(t, vpBytes) 140 require.NoError(t, err) 141 142 require.Equal(t, vp, vpFromJWT) 143 }) 144 145 t.Run("Decoding presentation from unsecured JWT with minimized fields of \"vp\" claim", func(t *testing.T) { 146 vpFromJWT, err := newTestPresentation(t, createPresUnsecuredJWT(t, vpBytes, true)) 147 148 require.NoError(t, err) 149 150 vp, err := newTestPresentation(t, vpBytes) 151 require.NoError(t, err) 152 153 require.Equal(t, vp, vpFromJWT) 154 }) 155 } 156 157 func TestParsePresentationWithVCJWT(t *testing.T) { 158 r := require.New(t) 159 160 // Create and encode VP. 161 issued := time.Date(2010, time.January, 1, 19, 23, 24, 0, time.UTC) 162 expired := time.Date(2020, time.January, 1, 19, 23, 24, 0, time.UTC) 163 164 vc := &Credential{ 165 Context: []string{ 166 "https://www.w3.org/2018/credentials/v1", 167 "https://www.w3.org/2018/credentials/examples/v1", 168 }, 169 ID: "http://example.edu/credentials/1872", 170 Types: []string{ 171 "VerifiableCredential", 172 "UniversityDegreeCredential", 173 }, 174 Subject: UniversityDegreeSubject{ 175 ID: "did:example:ebfeb1f712ebc6f1c276e12ec21", 176 Name: "Jayden Doe", 177 Spouse: "did:example:c276e12ec21ebfeb1f712ebc6f1", 178 Degree: UniversityDegree{ 179 Type: "BachelorDegree", 180 University: "MIT", 181 }, 182 }, 183 Issuer: Issuer{ 184 ID: "did:example:76e12ec712ebc6f1c221ebfeb1f", 185 CustomFields: CustomFields{"name": "Example University"}, 186 }, 187 Issued: util.NewTime(issued), 188 Expired: util.NewTime(expired), 189 Schemas: []TypedID{}, 190 } 191 192 vcJWTClaims, err := vc.JWTClaims(true) 193 r.NoError(err) 194 195 issuerSigner, err := newCryptoSigner(kms.RSARS256Type) 196 r.NoError(err) 197 198 vcJWS, err := vcJWTClaims.MarshalJWS(RS256, issuerSigner, "did:123#issuer-key") 199 r.NoError(err) 200 r.NotNil(vcJWS) 201 202 t.Run("Presentation with VC defined as JWS", func(t *testing.T) { 203 // Create and encode VP. 204 vp, err := NewPresentation(WithJWTCredentials(vcJWS)) 205 r.NoError(err) 206 207 vp.ID = "urn:uuid:2978344f-8596-4c3a-a978-8fcaba3903c" 208 vp.Holder = "did:example:fbfeb1f712ebc6f1c276e12ec21" 209 210 holderSigner, err := newCryptoSigner(kms.ED25519Type) 211 r.NoError(err) 212 213 jwtClaims, err := vp.JWTClaims([]string{}, true) 214 require.NoError(t, err) 215 216 vpJWS, err := jwtClaims.MarshalJWS(EdDSA, holderSigner, "did:123#holder-key") 217 r.NoError(err) 218 219 publicKeyFetcher := func(issuerID, keyID string) (*verifier.PublicKey, error) { 220 switch keyID { 221 case "holder-key": 222 return &verifier.PublicKey{ 223 Type: kms.ED25519, 224 Value: holderSigner.PublicKeyBytes(), 225 }, nil 226 case "issuer-key": 227 return &verifier.PublicKey{ 228 Type: kms.RSARS256, 229 Value: issuerSigner.PublicKeyBytes(), 230 }, nil 231 default: 232 return nil, errors.New("unexpected key") 233 } 234 } 235 236 // Decode VP 237 vpDecoded, err := newTestPresentation(t, []byte(vpJWS), WithPresPublicKeyFetcher(publicKeyFetcher)) 238 r.NoError(err) 239 vpCreds, err := vpDecoded.MarshalledCredentials() 240 r.NoError(err) 241 r.Len(vpCreds, 1) 242 243 vcDecoded, err := parseTestCredential(t, vpCreds[0], WithPublicKeyFetcher(publicKeyFetcher)) 244 r.NoError(err) 245 246 r.Equal(fmt.Sprintf("%q", vcJWS), vcDecoded.stringJSON(t)) 247 }) 248 249 t.Run("Presentation with VC defined as VC struct", func(t *testing.T) { 250 // Create and encode VP. 251 vp, err := NewPresentation(WithCredentials(vc)) 252 r.NoError(err) 253 254 vp.ID = "urn:uuid:5978344f-8596-4c3a-a978-8fcaba3903c" 255 vp.Holder = "did:example:abfeb1f712ebc6f1c276e12ec21" 256 257 holderSigner, err := newCryptoSigner(kms.ED25519Type) 258 r.NoError(err) 259 260 jwtClaims, err := vp.JWTClaims([]string{}, true) 261 require.NoError(t, err) 262 263 vpJWS, err := jwtClaims.MarshalJWS(EdDSA, holderSigner, "did:123#holder-key") 264 r.NoError(err) 265 266 // Decode VP 267 vpDecoded, err := newTestPresentation(t, []byte(vpJWS), WithPresPublicKeyFetcher( 268 SingleKey(holderSigner.PublicKeyBytes(), kms.ED25519))) 269 r.NoError(err) 270 vpCreds, err := vpDecoded.MarshalledCredentials() 271 r.NoError(err) 272 r.Len(vpCreds, 1) 273 274 vcDecoded, err := parseTestCredential(t, vpCreds[0]) 275 r.NoError(err) 276 277 r.Equal(vc.stringJSON(t), vcDecoded.stringJSON(t)) 278 }) 279 280 t.Run("Failed check of VC due to invalid JWS", func(t *testing.T) { 281 vp, err := NewPresentation(WithJWTCredentials(vcJWS)) 282 r.NoError(err) 283 284 vp.ID = "urn:uuid:0978344f-8596-4c3a-a978-8fcaba3903c" 285 vp.Holder = "did:example:ebfeb2f712ebc6f1c276e12ec21" 286 287 holderSigner, err := newCryptoSigner(kms.ED25519Type) 288 r.NoError(err) 289 290 jwtClaims, err := vp.JWTClaims([]string{}, true) 291 require.NoError(t, err) 292 293 vpJWS, err := jwtClaims.MarshalJWS(EdDSA, holderSigner, "did:123#holder-key") 294 r.NoError(err) 295 296 // Decode VP 297 vp, err = newTestPresentation(t, []byte(vpJWS), WithPresPublicKeyFetcher( 298 func(issuerID, keyID string) (*verifier.PublicKey, error) { 299 switch keyID { 300 case "holder-key": 301 return &verifier.PublicKey{ 302 Type: kms.ED25519, 303 Value: holderSigner.PublicKeyBytes(), 304 }, nil 305 case "issuer-key": 306 // here we return invalid public key 307 anotherPubKey, _, gerr := ed25519.GenerateKey(rand.Reader) 308 r.NoError(gerr) 309 310 return &verifier.PublicKey{ 311 Type: kms.ED25519, 312 Value: anotherPubKey, 313 }, nil 314 default: 315 r.NoError(err) 316 return nil, errors.New("unexpected key") 317 } 318 })) 319 r.Error(err) 320 r.Contains(err.Error(), "decode credentials of presentation") 321 r.Contains(err.Error(), "JWS decoding") 322 r.Nil(vp) 323 }) 324 } 325 326 func createPresJWS(t *testing.T, vpBytes []byte, minimize bool, signer Signer) []byte { 327 vp, err := newTestPresentation(t, vpBytes) 328 require.NoError(t, err) 329 330 jwtClaims, err := vp.JWTClaims([]string{}, minimize) 331 require.NoError(t, err) 332 333 vpJWT, err := jwtClaims.MarshalJWS(RS256, signer, vp.Holder+"#keys-"+keyID) 334 require.NoError(t, err) 335 336 return []byte(vpJWT) 337 } 338 339 func createPresKeyFetcher(pubKeyBytes []byte) func(issuerID string, keyID string) (*verifier.PublicKey, error) { 340 return func(issuerID, keyID string) (*verifier.PublicKey, error) { 341 return &verifier.PublicKey{ 342 Type: kms.RSARS256, 343 Value: pubKeyBytes, 344 }, nil 345 } 346 } 347 348 func createPresUnsecuredJWT(t *testing.T, cred []byte, minimize bool) []byte { 349 vp, err := newTestPresentation(t, cred) 350 require.NoError(t, err) 351 352 jwtClaims, err := vp.JWTClaims([]string{}, minimize) 353 require.NoError(t, err) 354 355 vpJWT, err := jwtClaims.MarshalUnsecuredJWT() 356 require.NoError(t, err) 357 358 return []byte(vpJWT) 359 }