github.com/hyperledger/aries-framework-go@v0.3.2/pkg/doc/verifiable/credential_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 "errors" 11 "fmt" 12 "testing" 13 "time" 14 15 "github.com/stretchr/testify/require" 16 17 "github.com/hyperledger/aries-framework-go/component/models/did/endpoint" 18 "github.com/hyperledger/aries-framework-go/pkg/doc/did" 19 "github.com/hyperledger/aries-framework-go/pkg/doc/signature/verifier" 20 "github.com/hyperledger/aries-framework-go/pkg/kms" 21 mockvdr "github.com/hyperledger/aries-framework-go/pkg/mock/vdr" 22 ) 23 24 const jwtTestCredential = ` 25 { 26 "@context": [ 27 "https://www.w3.org/2018/credentials/v1", 28 "https://www.w3.org/2018/credentials/examples/v1" 29 ], 30 "type": ["VerifiableCredential", "UniversityDegreeCredential"], 31 "credentialSubject": { 32 "id": "did:example:ebfeb1f712ebc6f1c276e12ec21", 33 "degree": { 34 "type": "BachelorDegree", 35 "university": "MIT" 36 } 37 }, 38 "issuer": { 39 "id": "did:example:76e12ec712ebc6f1c221ebfeb1f", 40 "name": "Example University" 41 }, 42 "issuanceDate": "2010-01-01T19:23:24Z", 43 "expirationDate": "2020-01-01T19:23:24Z" 44 } 45 ` 46 47 const keyID = "1" 48 49 func TestParseCredentialFromJWS(t *testing.T) { 50 testCred := []byte(jwtTestCredential) 51 52 ed25519Signer, err := newCryptoSigner(kms.ED25519Type) 53 require.NoError(t, err) 54 55 ed25519KeyFetcher := createDIDKeyFetcher(t, ed25519Signer.PublicKeyBytes(), "76e12ec712ebc6f1c221ebfeb1f") 56 57 rs256Signer, err := newCryptoSigner(kms.RSARS256Type) 58 require.NoError(t, err) 59 60 t.Run("Decoding credential from JWS", func(t *testing.T) { 61 vcFromJWT, err := parseTestCredential(t, 62 createEdDSAJWS(t, testCred, ed25519Signer, false), 63 WithPublicKeyFetcher(ed25519KeyFetcher)) 64 65 require.NoError(t, err) 66 67 vc, err := parseTestCredential(t, testCred) 68 require.NoError(t, err) 69 70 require.NotEqual(t, "", vcFromJWT.JWT) 71 vcFromJWT.JWT = "" 72 73 require.Equal(t, vc, vcFromJWT) 74 }) 75 76 t.Run("Decoding credential from JWS with minimized fields of \"vc\" claim", func(t *testing.T) { 77 vcFromJWT, err := parseTestCredential(t, 78 createEdDSAJWS(t, testCred, ed25519Signer, true), 79 WithPublicKeyFetcher(ed25519KeyFetcher)) 80 81 require.NoError(t, err) 82 83 vc, err := parseTestCredential(t, testCred) 84 require.NoError(t, err) 85 86 require.NotEqual(t, "", vcFromJWT.JWT) 87 vcFromJWT.JWT = "" 88 89 require.Equal(t, vc, vcFromJWT) 90 }) 91 92 t.Run("Failed JWT signature verification of credential", func(t *testing.T) { 93 vc, err := parseTestCredential(t, 94 createRS256JWS(t, testCred, rs256Signer, true), 95 // passing holder's key, while expecting issuer one 96 WithPublicKeyFetcher(func(issuerID, keyID string) (*verifier.PublicKey, error) { 97 holderSigner, err := newCryptoSigner(kms.RSARS256Type) 98 require.NoError(t, err) 99 100 return &verifier.PublicKey{ 101 Type: kms.RSARS256, 102 Value: holderSigner.PublicKeyBytes(), 103 }, nil 104 })) 105 106 require.Error(t, err) 107 require.Contains(t, err.Error(), "JWS decoding: unmarshal VC JWT claims") 108 require.Nil(t, vc) 109 }) 110 111 t.Run("Failed public key fetching", func(t *testing.T) { 112 vc, err := parseTestCredential(t, 113 createRS256JWS(t, testCred, rs256Signer, true), 114 115 WithPublicKeyFetcher(func(issuerID, keyID string) (*verifier.PublicKey, error) { 116 return nil, errors.New("test: public key is not found") 117 })) 118 119 require.Error(t, err) 120 require.Nil(t, vc) 121 }) 122 123 t.Run("Not defined public key fetcher", func(t *testing.T) { 124 vc, err := parseTestCredential(t, createRS256JWS(t, testCred, rs256Signer, true)) 125 126 require.Error(t, err) 127 require.Contains(t, err.Error(), "public key fetcher is not defined") 128 require.Nil(t, vc) 129 }) 130 } 131 132 func TestParseCredentialFromJWS_EdDSA(t *testing.T) { 133 vcBytes := []byte(jwtTestCredential) 134 135 signer, err := newCryptoSigner(kms.ED25519Type) 136 require.NoError(t, err) 137 138 vc, err := parseTestCredential(t, vcBytes) 139 require.NoError(t, err) 140 141 vcJWSStr := createEdDSAJWS(t, vcBytes, signer, false) 142 143 // unmarshal credential from JWS 144 vcFromJWS, err := parseTestCredential(t, 145 vcJWSStr, 146 WithPublicKeyFetcher(SingleKey(signer.PublicKeyBytes(), kms.ED25519))) 147 require.NoError(t, err) 148 149 require.NotEqual(t, "", vcFromJWS.JWT) 150 vcFromJWS.JWT = "" 151 152 // unmarshalled credential must be the same as original one 153 require.Equal(t, vc, vcFromJWS) 154 } 155 156 func TestParseCredentialFromUnsecuredJWT(t *testing.T) { 157 testCred := []byte(jwtTestCredential) 158 159 t.Run("Unsecured JWT decoding with no fields minimization", func(t *testing.T) { 160 vcFromJWT, err := parseTestCredential(t, createUnsecuredJWT(t, testCred, false)) 161 162 require.NoError(t, err) 163 164 vc, err := parseTestCredential(t, testCred) 165 require.NoError(t, err) 166 167 require.Equal(t, vc, vcFromJWT) 168 }) 169 170 t.Run("Unsecured JWT decoding with minimized fields", func(t *testing.T) { 171 vcFromJWT, err := parseTestCredential(t, createUnsecuredJWT(t, testCred, true)) 172 173 require.NoError(t, err) 174 175 vc, err := parseTestCredential(t, testCred) 176 require.NoError(t, err) 177 178 require.Equal(t, vc, vcFromJWT) 179 }) 180 } 181 182 func TestJwtWithExtension(t *testing.T) { 183 signer, err := newCryptoSigner(kms.RSARS256Type) 184 require.NoError(t, err) 185 186 keyFetcher := WithPublicKeyFetcher(func(issuerID, keyID string) (*verifier.PublicKey, error) { 187 return &verifier.PublicKey{ 188 Type: kms.RSARS256, 189 Value: signer.PublicKeyBytes(), 190 }, nil 191 }) 192 193 vcJWS := createRS256JWS(t, []byte(jwtTestCredential), signer, true) 194 195 // Decode to base credential. 196 cred, err := parseTestCredential(t, vcJWS, keyFetcher) 197 require.NoError(t, err) 198 require.NotNil(t, cred) 199 200 // Decode to the Credential extension. 201 udc, err := NewUniversityDegreeCredential(t, vcJWS, keyFetcher) 202 require.NoError(t, err) 203 require.NotNil(t, udc) 204 205 // Compare that base credentials are the same. 206 require.Equal(t, udc.Base, *cred) 207 } 208 209 func TestRefineVcIssuerFromJwtClaims(t *testing.T) { 210 t.Run("refine verifiable credential issuer defined by plain id", func(t *testing.T) { 211 vcMap := map[string]interface{}{ 212 "issuer": "id to override", 213 } 214 refineVCIssuerFromJWTClaims(vcMap, "did:example:76e12ec712ebc6f1c221ebfeb1f") 215 require.Equal(t, "did:example:76e12ec712ebc6f1c221ebfeb1f", vcMap["issuer"]) 216 }) 217 218 t.Run("refine verifiable credential issuer defined by structure", func(t *testing.T) { 219 issuerMap := map[string]interface{}{"id": "id to override", "name": "Example University"} 220 vcMap := map[string]interface{}{ 221 "issuer": issuerMap, 222 } 223 refineVCIssuerFromJWTClaims(vcMap, "did:example:76e12ec712ebc6f1c221ebfeb1f") 224 // issuer id is refined 225 require.Equal(t, "did:example:76e12ec712ebc6f1c221ebfeb1f", issuerMap["id"]) 226 // issuer name remains the same (i.e. not erased) 227 require.Equal(t, "Example University", issuerMap["name"]) 228 }) 229 230 t.Run("refine not defined verifiable credential issuer", func(t *testing.T) { 231 vcMap := make(map[string]interface{}) 232 refineVCIssuerFromJWTClaims(vcMap, "did:example:76e12ec712ebc6f1c221ebfeb1f") 233 require.Equal(t, "did:example:76e12ec712ebc6f1c221ebfeb1f", vcMap["issuer"]) 234 }) 235 } 236 237 func createDIDKeyFetcher(t *testing.T, pub ed25519.PublicKey, didID string) PublicKeyFetcher { 238 const ( 239 didFormat = "did:%s:%s" 240 didPKID = "%s#keys-%d" 241 didServiceID = "%s#endpoint-%d" 242 method = "example" 243 ) 244 245 id := fmt.Sprintf(didFormat, method, didID) 246 pubKeyID := fmt.Sprintf(didPKID, id, 1) 247 pubKey := did.NewVerificationMethodFromBytes(pubKeyID, "Ed25519VerificationKey2018", id, pub) 248 services := []did.Service{ 249 { 250 ID: fmt.Sprintf(didServiceID, id, 1), 251 Type: "did-communication", 252 ServiceEndpoint: endpoint.NewDIDCommV1Endpoint("http://localhost:47582"), 253 Priority: 0, 254 RecipientKeys: []string{pubKeyID}, 255 }, 256 } 257 createdTime := time.Now() 258 didDoc := &did.Doc{ 259 Context: []string{did.ContextV1}, 260 ID: id, 261 VerificationMethod: []did.VerificationMethod{*pubKey}, 262 Service: services, 263 Created: &createdTime, 264 Updated: &createdTime, 265 } 266 267 v := &mockvdr.MockVDRegistry{ 268 ResolveValue: didDoc, 269 } 270 271 resolver := NewVDRKeyResolver(v) 272 require.NotNil(t, resolver) 273 274 return resolver.resolvePublicKey 275 } 276 277 func createRS256JWS(t *testing.T, cred []byte, signer Signer, minimize bool) []byte { 278 vc, err := parseTestCredential(t, cred) 279 require.NoError(t, err) 280 281 jwtClaims, err := vc.JWTClaims(minimize) 282 require.NoError(t, err) 283 vcJWT, err := jwtClaims.MarshalJWS(RS256, signer, vc.Issuer.ID+"#keys-"+keyID) 284 require.NoError(t, err) 285 286 return []byte(vcJWT) 287 } 288 289 func createEdDSAJWS(t *testing.T, cred []byte, signer Signer, minimize bool) []byte { 290 vc, err := parseTestCredential(t, cred) 291 require.NoError(t, err) 292 293 jwtClaims, err := vc.JWTClaims(minimize) 294 require.NoError(t, err) 295 vcJWT, err := jwtClaims.MarshalJWS(EdDSA, signer, vc.Issuer.ID+"#keys-"+keyID) 296 require.NoError(t, err) 297 298 return []byte(vcJWT) 299 } 300 301 func createUnsecuredJWT(t *testing.T, cred []byte, minimize bool) []byte { 302 vc, err := parseTestCredential(t, cred) 303 require.NoError(t, err) 304 305 jwtClaims, err := vc.JWTClaims(minimize) 306 require.NoError(t, err) 307 vcJWT, err := jwtClaims.MarshalUnsecuredJWT() 308 require.NoError(t, err) 309 310 return []byte(vcJWT) 311 }