github.com/hyperledger/aries-framework-go@v0.3.2/pkg/wallet/wallet_test.go (about) 1 /* 2 Copyright SecureKey Technologies Inc. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package wallet 8 9 import ( 10 "crypto/ecdsa" 11 "crypto/ed25519" 12 "crypto/elliptic" 13 "crypto/rand" 14 "crypto/sha256" 15 _ "embed" 16 "encoding/base64" 17 "encoding/json" 18 "errors" 19 "fmt" 20 "net/http" 21 "strings" 22 "testing" 23 "time" 24 25 "github.com/btcsuite/btcutil/base58" 26 "github.com/google/uuid" 27 "github.com/stretchr/testify/require" 28 29 "github.com/hyperledger/aries-framework-go/component/storage/edv" 30 "github.com/hyperledger/aries-framework-go/internal/testdata" 31 "github.com/hyperledger/aries-framework-go/pkg/crypto/primitive/bbs12381g2pub" 32 "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto" 33 "github.com/hyperledger/aries-framework-go/pkg/doc/did" 34 "github.com/hyperledger/aries-framework-go/pkg/doc/jwt" 35 "github.com/hyperledger/aries-framework-go/pkg/doc/presexch" 36 "github.com/hyperledger/aries-framework-go/pkg/doc/util" 37 "github.com/hyperledger/aries-framework-go/pkg/doc/verifiable" 38 vdrapi "github.com/hyperledger/aries-framework-go/pkg/framework/aries/api/vdr" 39 "github.com/hyperledger/aries-framework-go/pkg/internal/ldtestutil" 40 "github.com/hyperledger/aries-framework-go/pkg/kms" 41 "github.com/hyperledger/aries-framework-go/pkg/kms/webkms" 42 cryptomock "github.com/hyperledger/aries-framework-go/pkg/mock/crypto" 43 mockkms "github.com/hyperledger/aries-framework-go/pkg/mock/kms" 44 mockprovider "github.com/hyperledger/aries-framework-go/pkg/mock/provider" 45 "github.com/hyperledger/aries-framework-go/pkg/mock/secretlock" 46 mockstorage "github.com/hyperledger/aries-framework-go/pkg/mock/storage" 47 mockvdr "github.com/hyperledger/aries-framework-go/pkg/mock/vdr" 48 "github.com/hyperledger/aries-framework-go/pkg/secretlock/local/masterlock/pbkdf2" 49 "github.com/hyperledger/aries-framework-go/pkg/vdr/fingerprint" 50 "github.com/hyperledger/aries-framework-go/pkg/vdr/key" 51 "github.com/hyperledger/aries-framework-go/spi/storage" 52 ) 53 54 // nolint: lll 55 const ( 56 sampleUserID = "sample-user01" 57 sampleFakeTkn = "fake-auth-tkn" 58 toBeImplementedErr = "to be implemented" 59 sampleWalletErr = "sample wallet err" 60 sampleCreatedDate = "2020-12-25" 61 sampleChallenge = "sample-challenge" 62 sampleDomain = "sample-domain" 63 sampleInvalidDIDID = "did:key:z6MkjRagNiMu91DduvCvgEsqLZDVzrJzFrwahc4tXLt9DoHdI" 64 sampleInvalidDIDContent = `{ 65 "@context": ["https://w3id.org/did/v1"], 66 "id": "did:example:sampleInvalidDIDContent" 67 }` 68 sampleVerificationMethod = "did:key:z6MknC1wwS6DEYwtGbZZo2QvjQjkh2qSBjb4GYmbye8dv4S5#z6MknC1wwS6DEYwtGbZZo2QvjQjkh2qSBjb4GYmbye8dv4S5" 69 didKey = "did:key:z6MknC1wwS6DEYwtGbZZo2QvjQjkh2qSBjb4GYmbye8dv4S5" 70 pkBase58 = "2MP5gWCnf67jvW3E4Lz8PpVrDWAXMYY1sDxjnkEnKhkkbKD7yP2mkVeyVpu5nAtr3TeDgMNjBPirk2XcQacs3dvZ" 71 kid = "z6MknC1wwS6DEYwtGbZZo2QvjQjkh2qSBjb4GYmbye8dv4S5" 72 didKeyBBS = "did:key:zUC72c7u4BYVmfYinDceXkNAwzPEyuEE23kUmJDjLy8495KH3pjLwFhae1Fww9qxxRdLnS2VNNwni6W3KbYZKsicDtiNNEp76fYWR6HCD8jAz6ihwmLRjcHH6kB294Xfg1SL1qQ" 73 pkBBSBase58 = "6gsgGpdx7p1nYoKJ4b5fKt1xEomWdnemg9nJFX6mqNCh" 74 keyIDBBS = "zUC72c7u4BYVmfYinDceXkNAwzPEyuEE23kUmJDjLy8495KH3pjLwFhae1Fww9qxxRdLnS2VNNwni6W3KbYZKsicDtiNNEp76fYWR6HCD8jAz6ihwmLRjcHH6kB294Xfg1SL1qQ" 75 sampleEDVServerURL = "sample-edv-url" 76 sampleEDVVaultID = "sample-edv-vault-id" 77 sampleEDVEncryptionKID = "sample-edv-encryption-kid" 78 sampleEDVMacKID = "sample-edv-mac-kid" 79 ) 80 81 func TestCreate(t *testing.T) { 82 t.Run("test create new wallet using local kms passphrase", func(t *testing.T) { 83 mockctx := newMockProvider(t) 84 err := CreateProfile(sampleUserID, mockctx, WithPassphrase(samplePassPhrase)) 85 require.NoError(t, err) 86 require.NoError(t, ProfileExists(sampleUserID, mockctx)) 87 88 wallet, err := New(sampleUserID, mockctx) 89 require.NoError(t, err) 90 require.NotEmpty(t, wallet) 91 }) 92 93 t.Run("test create new wallet using local kms secret lock service", func(t *testing.T) { 94 mockctx := newMockProvider(t) 95 err := CreateProfile(sampleUserID, mockctx, WithSecretLockService(&secretlock.MockSecretLock{})) 96 require.NoError(t, err) 97 98 wallet, err := New(sampleUserID, mockctx) 99 require.NoError(t, err) 100 require.NotEmpty(t, wallet) 101 }) 102 103 t.Run("test create new wallet using remote kms key server URL", func(t *testing.T) { 104 mockctx := newMockProvider(t) 105 err := CreateProfile(sampleUserID, mockctx, WithKeyServerURL(sampleKeyServerURL)) 106 require.NoError(t, err) 107 108 wallet, err := New(sampleUserID, mockctx) 109 require.NoError(t, err) 110 require.NotEmpty(t, wallet) 111 }) 112 113 t.Run("test create new wallet using remote kms key server URL & EDV", func(t *testing.T) { 114 mockctx := newMockProvider(t) 115 err := CreateProfile(sampleUserID, mockctx, WithKeyServerURL(sampleKeyServerURL), 116 WithEDVStorage(sampleEDVServerURL, sampleEDVVaultID, sampleEDVEncryptionKID, sampleEDVMacKID)) 117 require.NoError(t, err) 118 119 wallet, err := New(sampleUserID, mockctx) 120 require.NoError(t, err) 121 require.NotEmpty(t, wallet) 122 require.NotEmpty(t, wallet.profile.EDVConf) 123 require.Equal(t, wallet.profile.EDVConf.ServerURL, sampleEDVServerURL) 124 require.Equal(t, wallet.profile.EDVConf.VaultID, sampleEDVVaultID) 125 require.Equal(t, wallet.profile.EDVConf.EncryptionKeyID, sampleEDVEncryptionKID) 126 require.Equal(t, wallet.profile.EDVConf.MACKeyID, sampleEDVMacKID) 127 }) 128 129 t.Run("test create new wallet failure", func(t *testing.T) { 130 mockctx := newMockProvider(t) 131 err := CreateProfile(sampleUserID, mockctx) 132 require.Error(t, err) 133 require.Contains(t, err.Error(), "invalid create profile options") 134 135 require.True(t, errors.Is(ProfileExists(sampleUserID, mockctx), ErrProfileNotFound)) 136 137 wallet, err := New(sampleUserID, mockctx) 138 require.Error(t, err) 139 require.Empty(t, wallet) 140 }) 141 142 t.Run("test create new wallet failure - create store error", func(t *testing.T) { 143 mockctx := newMockProvider(t) 144 mockctx.StorageProviderValue = &mockstorage.MockStoreProvider{ 145 ErrOpenStoreHandle: fmt.Errorf(sampleWalletErr), 146 } 147 148 err := CreateProfile(sampleUserID, mockctx, WithKeyServerURL(sampleKeyServerURL)) 149 require.Error(t, err) 150 require.Contains(t, err.Error(), sampleWalletErr) 151 152 err = ProfileExists(sampleUserID, mockctx) 153 require.Error(t, err) 154 require.Contains(t, err.Error(), sampleWalletErr) 155 156 wallet, err := New(sampleUserID, mockctx) 157 require.Error(t, err) 158 require.Empty(t, wallet) 159 }) 160 161 t.Run("test create new wallet failure - save profile error", func(t *testing.T) { 162 mockctx := newMockProvider(t) 163 mockctx.StorageProviderValue = &mockstorage.MockStoreProvider{ 164 Store: &mockstorage.MockStore{ 165 ErrPut: fmt.Errorf(sampleWalletErr), 166 }, 167 } 168 169 err := CreateProfile(sampleUserID, mockctx, WithKeyServerURL(sampleKeyServerURL)) 170 require.Error(t, err) 171 require.Contains(t, err.Error(), sampleWalletErr) 172 173 wallet, err := New(sampleUserID, mockctx) 174 require.Error(t, err) 175 require.Empty(t, wallet) 176 }) 177 } 178 179 func TestUpdate(t *testing.T) { 180 t.Run("test update wallet using local kms passphrase", func(t *testing.T) { 181 mockctx := newMockProvider(t) 182 createSampleProfile(t, mockctx) 183 184 err := UpdateProfile(sampleUserID, mockctx, WithPassphrase(samplePassPhrase)) 185 require.NoError(t, err) 186 187 wallet, err := New(sampleUserID, mockctx) 188 require.NoError(t, err) 189 require.NotEmpty(t, wallet) 190 require.NotEmpty(t, wallet.profile.MasterLockCipher) 191 }) 192 193 t.Run("test update wallet using local kms secret lock service", func(t *testing.T) { 194 mockctx := newMockProvider(t) 195 createSampleProfile(t, mockctx) 196 197 err := UpdateProfile(sampleUserID, mockctx, WithSecretLockService(&secretlock.MockSecretLock{})) 198 require.NoError(t, err) 199 200 wallet, err := New(sampleUserID, mockctx) 201 require.NoError(t, err) 202 require.NotEmpty(t, wallet) 203 }) 204 205 t.Run("test update wallet using remote kms key server URL", func(t *testing.T) { 206 mockctx := newMockProvider(t) 207 createSampleProfile(t, mockctx) 208 209 err := UpdateProfile(sampleUserID, mockctx, WithKeyServerURL(sampleKeyServerURL)) 210 require.NoError(t, err) 211 212 wallet, err := New(sampleUserID, mockctx) 213 require.NoError(t, err) 214 require.NotEmpty(t, wallet) 215 require.Empty(t, wallet.profile.MasterLockCipher) 216 require.NotEmpty(t, wallet.profile.KeyServerURL) 217 }) 218 219 t.Run("test update wallet profile edv settings", func(t *testing.T) { 220 mockctx := newMockProvider(t) 221 createSampleProfile(t, mockctx) 222 223 err := UpdateProfile(sampleUserID, mockctx, WithKeyServerURL(sampleKeyServerURL), 224 WithEDVStorage(sampleEDVServerURL, sampleEDVVaultID, sampleEDVEncryptionKID, sampleEDVMacKID)) 225 require.NoError(t, err) 226 227 wallet, err := New(sampleUserID, mockctx) 228 require.NoError(t, err) 229 require.NotEmpty(t, wallet) 230 require.NotEmpty(t, wallet.profile.EDVConf) 231 require.Equal(t, wallet.profile.EDVConf.ServerURL, sampleEDVServerURL) 232 require.Equal(t, wallet.profile.EDVConf.VaultID, sampleEDVVaultID) 233 require.Equal(t, wallet.profile.EDVConf.EncryptionKeyID, sampleEDVEncryptionKID) 234 require.Equal(t, wallet.profile.EDVConf.MACKeyID, sampleEDVMacKID) 235 }) 236 237 t.Run("test update wallet failure", func(t *testing.T) { 238 mockctx := newMockProvider(t) 239 createSampleProfile(t, mockctx) 240 241 err := UpdateProfile(sampleUserID, mockctx) 242 require.Error(t, err) 243 require.Contains(t, err.Error(), "invalid create profile options") 244 245 wallet, err := New(sampleUserID, mockctx) 246 require.NoError(t, err) 247 require.NotEmpty(t, wallet) 248 require.NotEmpty(t, wallet.profile.MasterLockCipher) 249 }) 250 251 t.Run("test update wallet failure - profile doesn't exists", func(t *testing.T) { 252 mockctx := newMockProvider(t) 253 err := UpdateProfile(sampleUserID, mockctx) 254 require.Error(t, err) 255 require.Contains(t, err.Error(), "profile does not exist") 256 257 wallet, err := New(sampleUserID, mockctx) 258 require.Error(t, err) 259 require.Empty(t, wallet) 260 }) 261 262 t.Run("test update wallet failure - create store error", func(t *testing.T) { 263 mockctx := newMockProvider(t) 264 mockctx.StorageProviderValue = &mockstorage.MockStoreProvider{ 265 ErrOpenStoreHandle: fmt.Errorf(sampleWalletErr), 266 } 267 268 err := UpdateProfile(sampleUserID, mockctx, WithKeyServerURL(sampleKeyServerURL)) 269 require.Error(t, err) 270 require.Contains(t, err.Error(), sampleWalletErr) 271 272 wallet, err := New(sampleUserID, mockctx) 273 require.Error(t, err) 274 require.Empty(t, wallet) 275 }) 276 277 t.Run("test update wallet failure - save profile error", func(t *testing.T) { 278 mockctx := newMockProvider(t) 279 createSampleProfile(t, mockctx) 280 281 mockctx.StorageProviderValue.(*mockstorage.MockStoreProvider).Store.ErrPut = fmt.Errorf(sampleWalletErr) 282 283 err := UpdateProfile(sampleUserID, mockctx, WithKeyServerURL(sampleKeyServerURL)) 284 require.Error(t, err) 285 require.Contains(t, err.Error(), sampleWalletErr) 286 287 wallet, err := New(sampleUserID, mockctx) 288 require.NoError(t, err) 289 require.NotEmpty(t, wallet) 290 require.Empty(t, wallet.profile.KeyServerURL) 291 require.NotEmpty(t, wallet.profile.MasterLockCipher) 292 }) 293 294 t.Run("test update wallet failure - save edv settings error", func(t *testing.T) { 295 mockctx := newMockProvider(t) 296 createSampleProfile(t, mockctx) 297 298 err := UpdateProfile(sampleUserID, mockctx, WithKeyServerURL(sampleKeyServerURL), 299 WithEDVStorage(sampleEDVServerURL, "", sampleEDVEncryptionKID, sampleEDVMacKID)) 300 require.Error(t, err) 301 require.Contains(t, err.Error(), "failed to update EDV configuration") 302 }) 303 } 304 305 func TestCreateDataVaultKeyPairs(t *testing.T) { 306 t.Run("successfully create EDV key pair", func(t *testing.T) { 307 mockctx := newMockProvider(t) 308 309 // create a wallet profile 310 err := CreateProfile(sampleUserID, mockctx, WithPassphrase(samplePassPhrase), 311 WithEDVStorage(sampleEDVServerURL, sampleEDVVaultID, "", "")) 312 require.NoError(t, err) 313 314 err = CreateDataVaultKeyPairs(sampleUserID, mockctx, WithUnlockByPassphrase(samplePassPhrase)) 315 require.NoError(t, err) 316 317 wallet, err := New(sampleUserID, mockctx) 318 require.NoError(t, err) 319 require.NotEmpty(t, wallet) 320 require.NotEmpty(t, wallet.profile.EDVConf.EncryptionKeyID) 321 require.NotEmpty(t, wallet.profile.EDVConf.MACKeyID) 322 323 // call again to replace existing settings 324 err = CreateDataVaultKeyPairs(sampleUserID, mockctx, WithUnlockByPassphrase(samplePassPhrase)) 325 require.NoError(t, err) 326 327 wallet2, err := New(sampleUserID, mockctx) 328 require.NoError(t, err) 329 require.NotEmpty(t, wallet2) 330 require.NotEmpty(t, wallet2.profile.EDVConf.EncryptionKeyID) 331 require.NotEmpty(t, wallet2.profile.EDVConf.MACKeyID) 332 333 require.NotEqual(t, wallet.profile.EDVConf.EncryptionKeyID, wallet2.profile.EDVConf.EncryptionKeyID) 334 require.NotEqual(t, wallet.profile.EDVConf.MACKeyID, wallet2.profile.EDVConf.MACKeyID) 335 }) 336 337 t.Run("successfully create key pair failures", func(t *testing.T) { 338 mockctx := newMockProvider(t) 339 340 // test create a wallet profile without EDV settings 341 err := CreateProfile(sampleUserID, mockctx, WithPassphrase(samplePassPhrase)) 342 require.NoError(t, err) 343 344 err = CreateDataVaultKeyPairs(sampleUserID, mockctx, WithUnlockByPassphrase(samplePassPhrase)) 345 require.Error(t, err) 346 require.Contains(t, err.Error(), "invalid operation") 347 348 // test store errors 349 mockctx = newMockProvider(t) 350 mockctx.StorageProviderValue = &mockstorage.MockStoreProvider{ 351 ErrOpenStoreHandle: errors.New(sampleWalletErr), 352 } 353 354 err = CreateDataVaultKeyPairs(sampleUserID, mockctx, WithUnlockByPassphrase(samplePassPhrase)) 355 require.Error(t, err) 356 require.Contains(t, err.Error(), "failed to get store") 357 358 // invalid user profile 359 mockctx = newMockProvider(t) 360 err = CreateDataVaultKeyPairs(sampleUserID, mockctx, WithUnlockByPassphrase(samplePassPhrase)) 361 require.Error(t, err) 362 require.Contains(t, err.Error(), "failed to get wallet user profile") 363 364 // invalid auth 365 mockctx = newMockProvider(t) 366 367 err = CreateProfile(sampleUserID, mockctx, WithPassphrase(samplePassPhrase), 368 WithEDVStorage(sampleEDVServerURL, sampleEDVVaultID, "", "")) 369 require.NoError(t, err) 370 371 err = CreateDataVaultKeyPairs(sampleUserID, mockctx, WithUnlockByPassphrase("invalid")) 372 require.Error(t, err) 373 require.Contains(t, err.Error(), "message authentication failed") 374 375 // test create key pair error 376 mockctx = newMockProvider(t) 377 378 err = CreateProfile(sampleUserID, mockctx, WithPassphrase(samplePassPhrase), 379 WithEDVStorage(sampleEDVServerURL, sampleEDVVaultID, "", "")) 380 require.NoError(t, err) 381 382 mockStPvdr, ok := mockctx.StorageProviderValue.(*mockstorage.MockStoreProvider) 383 require.True(t, ok) 384 mockStPvdr.Store.ErrPut = errors.New(sampleWalletErr) 385 386 err = CreateDataVaultKeyPairs(sampleUserID, mockctx, WithUnlockByPassphrase(samplePassPhrase)) 387 require.Error(t, err) 388 require.Contains(t, err.Error(), "failed to create key pairs") 389 }) 390 391 t.Run("fail to create new KMS Aries provider wrapper", func(t *testing.T) { 392 testProfile := profile{EDVConf: &edvConf{}} 393 394 testProfileBytes, err := json.Marshal(testProfile) 395 require.NoError(t, err) 396 397 mockContext := &mockprovider.Provider{ 398 StorageProviderValue: &mockstorage.MockStoreProvider{ 399 FailNamespace: kms.AriesWrapperStoreName, 400 Store: &mockstorage.MockStore{ 401 Store: map[string]mockstorage.DBEntry{ 402 "vcwallet_usr_sample-user01": {Value: testProfileBytes}, 403 }, 404 }, 405 }, 406 } 407 408 err = CreateDataVaultKeyPairs(sampleUserID, mockContext) 409 require.EqualError(t, err, "failed to open store for name space kmsdb") 410 }) 411 412 t.Run("test update profile errors", func(t *testing.T) { 413 kmgr := &mockkms.KeyManager{CreateKeyFn: func(kt kms.KeyType) (s string, i interface{}, e error) { 414 if kt == kms.HMACSHA256Tag256Type { 415 return "", nil, errors.New(sampleWalletErr) 416 } 417 return "", nil, nil 418 }} 419 420 err := updateProfile(kmgr, &profile{EDVConf: &edvConf{}}) 421 require.Error(t, err) 422 require.Contains(t, err.Error(), "failed to create EDV MAC key pair") 423 424 kmgr = &mockkms.KeyManager{CreateKeyFn: func(kt kms.KeyType) (s string, i interface{}, e error) { 425 if kt == kms.NISTP256ECDHKWType { 426 return "", nil, errors.New(sampleWalletErr) 427 } 428 return "", nil, nil 429 }} 430 431 err = updateProfile(kmgr, &profile{EDVConf: &edvConf{}}) 432 require.Error(t, err) 433 require.Contains(t, err.Error(), "failed to create EDV encryption key pair") 434 }) 435 } 436 437 func TestNew(t *testing.T) { 438 t.Run("test get wallet by user", func(t *testing.T) { 439 mockctx := newMockProvider(t) 440 // create a wallet 441 err := CreateProfile(sampleUserID, mockctx, WithPassphrase(samplePassPhrase)) 442 require.NoError(t, err) 443 444 wallet, err := New(sampleUserID, mockctx) 445 require.NoError(t, err) 446 require.NotEmpty(t, wallet) 447 }) 448 449 t.Run("test get wallet by invalid userID", func(t *testing.T) { 450 mockctx := newMockProvider(t) 451 err := CreateProfile(sampleUserID, mockctx, WithPassphrase(samplePassPhrase)) 452 require.NoError(t, err) 453 454 wallet, err := New(sampleUserID+"invalid", mockctx) 455 require.Empty(t, wallet) 456 require.Error(t, err) 457 require.Contains(t, err.Error(), "profile does not exist") 458 }) 459 460 t.Run("test get wallet failure - save profile error", func(t *testing.T) { 461 mockctx := newMockProvider(t) 462 mockctx.StorageProviderValue = &mockstorage.MockStoreProvider{ 463 ErrOpenStoreHandle: fmt.Errorf(sampleWalletErr), 464 } 465 466 wallet, err := New(sampleUserID, mockctx) 467 require.Error(t, err) 468 require.Empty(t, wallet) 469 require.Contains(t, err.Error(), sampleWalletErr) 470 }) 471 } 472 473 func TestWallet_OpenClose(t *testing.T) { 474 t.Run("test open & close wallet using local kms passphrase", func(t *testing.T) { 475 mockctx := newMockProvider(t) 476 err := CreateProfile(sampleUserID, mockctx, WithPassphrase(samplePassPhrase)) 477 require.NoError(t, err) 478 479 wallet, err := New(sampleUserID, mockctx) 480 require.NoError(t, err) 481 require.NotEmpty(t, wallet) 482 483 // get token 484 token, err := wallet.Open(WithUnlockByPassphrase(samplePassPhrase), WithUnlockExpiry(500*time.Millisecond)) 485 require.NoError(t, err) 486 require.NotEmpty(t, token) 487 488 // try again 489 token, err = wallet.Open(WithUnlockByPassphrase(samplePassPhrase)) 490 require.Empty(t, token) 491 require.Error(t, err) 492 require.Equal(t, err, ErrAlreadyUnlocked) 493 494 // close wallet 495 require.True(t, wallet.Close()) 496 require.False(t, wallet.Close()) 497 498 // try to open with wrong passphrase 499 token, err = wallet.Open(WithUnlockByPassphrase(samplePassPhrase + "wrong")) 500 require.Empty(t, token) 501 require.Error(t, err) 502 require.Contains(t, err.Error(), "message authentication failed") 503 }) 504 505 t.Run("test open & close wallet using secret lock service", func(t *testing.T) { 506 mockctx := newMockProvider(t) 507 masterLock, err := pbkdf2.NewMasterLock(samplePassPhrase, sha256.New, 0, nil) 508 require.NoError(t, err) 509 510 err = CreateProfile(sampleUserID, mockctx, WithSecretLockService(masterLock)) 511 require.NoError(t, err) 512 513 wallet, err := New(sampleUserID, mockctx) 514 require.NoError(t, err) 515 require.NotEmpty(t, wallet) 516 517 // get token 518 token, err := wallet.Open(WithUnlockBySecretLockService(masterLock)) 519 require.NoError(t, err) 520 require.NotEmpty(t, token) 521 522 // try again 523 token, err = wallet.Open(WithUnlockBySecretLockService(masterLock)) 524 require.Empty(t, token) 525 require.Error(t, err) 526 require.Equal(t, err, ErrAlreadyUnlocked) 527 528 // close wallet 529 require.True(t, wallet.Close()) 530 require.False(t, wallet.Close()) 531 532 // try to open with wrong secret lock service 533 badLock, err := pbkdf2.NewMasterLock(samplePassPhrase+"wrong", sha256.New, 0, nil) 534 require.NoError(t, err) 535 536 token, err = wallet.Open(WithUnlockBySecretLockService(badLock)) 537 require.Empty(t, token) 538 require.Error(t, err) 539 require.Contains(t, err.Error(), "message authentication failed") 540 }) 541 542 t.Run("test open & close wallet using remote kms URL & auth token option", func(t *testing.T) { 543 mockctx := newMockProvider(t) 544 err := CreateProfile(sampleUserID, mockctx, WithKeyServerURL(sampleKeyServerURL)) 545 require.NoError(t, err) 546 547 wallet, err := New(sampleUserID, mockctx) 548 require.NoError(t, err) 549 require.NotEmpty(t, wallet) 550 551 // get token 552 token, err := wallet.Open(WithUnlockByAuthorizationToken(sampleRemoteKMSAuth)) 553 require.NoError(t, err) 554 require.NotEmpty(t, token) 555 556 // try again 557 token, err = wallet.Open(WithUnlockByAuthorizationToken(sampleRemoteKMSAuth)) 558 require.Empty(t, token) 559 require.Error(t, err) 560 require.Equal(t, err, ErrAlreadyUnlocked) 561 562 // close wallet 563 require.True(t, wallet.Close()) 564 require.False(t, wallet.Close()) 565 }) 566 567 t.Run("test open & close wallet using remote kms URL & auth header option", func(t *testing.T) { 568 mockctx := newMockProvider(t) 569 err := CreateProfile(sampleUserID, mockctx, WithKeyServerURL(sampleKeyServerURL)) 570 require.NoError(t, err) 571 572 wallet, err := New(sampleUserID, mockctx) 573 require.NoError(t, err) 574 require.NotEmpty(t, wallet) 575 576 // get token 577 token, err := wallet.Open(WithUnlockWebKMSOptions( 578 webkms.WithHeaders(func(req *http.Request) (*http.Header, error) { 579 req.Header.Set("authorization", fmt.Sprintf("Bearer %s", sampleRemoteKMSAuth)) 580 581 return &req.Header, nil 582 }), 583 )) 584 require.NoError(t, err) 585 require.NotEmpty(t, token) 586 587 // try again 588 token, err = wallet.Open(WithUnlockWebKMSOptions( 589 webkms.WithHeaders(func(req *http.Request) (*http.Header, error) { 590 req.Header.Set("authorization", fmt.Sprintf("Bearer %s", sampleRemoteKMSAuth)) 591 592 return &req.Header, nil 593 }), 594 )) 595 require.Empty(t, token) 596 require.Error(t, err) 597 require.Equal(t, err, ErrAlreadyUnlocked) 598 599 // close wallet 600 require.True(t, wallet.Close()) 601 require.False(t, wallet.Close()) 602 }) 603 604 t.Run("test open & close wallet using EDV options", func(t *testing.T) { 605 mockctx := newMockProvider(t) 606 user := uuid.New().String() 607 608 // create profile 609 err := CreateProfile(user, mockctx, WithPassphrase(samplePassPhrase), 610 WithEDVStorage(sampleEDVServerURL, sampleEDVVaultID, sampleEDVEncryptionKID, sampleEDVMacKID)) 611 require.NoError(t, err) 612 613 // create key pairs 614 err = CreateDataVaultKeyPairs(user, mockctx, WithUnlockByPassphrase(samplePassPhrase)) 615 require.NoError(t, err) 616 617 wallet, err := New(user, mockctx) 618 require.NoError(t, err) 619 require.NotEmpty(t, wallet) 620 621 token, err := wallet.Open(WithUnlockByPassphrase(samplePassPhrase), WithUnlockEDVOptions( 622 edv.WithFullDocumentsReturnedFromQueries(), edv.WithBatchEndpointExtension(), 623 )) 624 require.NoError(t, err) 625 require.NotEmpty(t, token) 626 627 // try again 628 token, err = wallet.Open(WithUnlockByPassphrase(samplePassPhrase)) 629 require.Empty(t, token) 630 require.Error(t, err) 631 require.Equal(t, err, ErrAlreadyUnlocked) 632 633 // close wallet 634 require.True(t, wallet.Close()) 635 require.False(t, wallet.Close()) 636 }) 637 638 t.Run("test opened wallet between multliple instances", func(t *testing.T) { 639 mockctx := newMockProvider(t) 640 err := CreateProfile(sampleUserID, mockctx, WithPassphrase(samplePassPhrase)) 641 require.NoError(t, err) 642 643 wallet1, err := New(sampleUserID, mockctx) 644 require.NoError(t, err) 645 require.NotEmpty(t, wallet1) 646 647 // get token 648 token, err := wallet1.Open(WithUnlockByPassphrase(samplePassPhrase), WithUnlockExpiry(500*time.Millisecond)) 649 require.NoError(t, err) 650 require.NotEmpty(t, token) 651 652 // create new instance for same profile 653 wallet2, err := New(sampleUserID, mockctx) 654 require.NoError(t, err) 655 require.NotEmpty(t, wallet2) 656 657 // no need to unlock again since token is shared 658 require.NoError(t, wallet2.Add(token, Metadata, []byte(sampleContentValid))) 659 660 // close first instance 661 wallet1.Close() 662 require.Error(t, wallet2.Add(token, Metadata, []byte(sampleContentNoID))) 663 }) 664 665 t.Run("test open wallet failure when store open fails", func(t *testing.T) { 666 mockctx := newMockProvider(t) 667 err := CreateProfile(sampleUserID, mockctx, WithKeyServerURL(sampleKeyServerURL)) 668 require.NoError(t, err) 669 670 wallet, err := New(sampleUserID, mockctx) 671 require.NoError(t, err) 672 require.NotEmpty(t, wallet) 673 674 // corrupt content store 675 wallet.contents = newContentStore(&mockstorage.MockStoreProvider{ 676 ErrOpenStoreHandle: fmt.Errorf(sampleWalletErr), 677 }, createTestDocumentLoader(t), wallet.profile) 678 679 // get token 680 token, err := wallet.Open(WithUnlockByAuthorizationToken(sampleRemoteKMSAuth)) 681 require.Error(t, err) 682 require.Contains(t, err.Error(), "failed to open store : sample wallet err") 683 require.Empty(t, token) 684 685 // close wallet 686 require.False(t, wallet.Close()) 687 }) 688 } 689 690 func TestWallet_Export(t *testing.T) { 691 mockctx := newMockProvider(t) 692 err := CreateProfile(sampleUserID, mockctx, WithKeyServerURL(sampleKeyServerURL)) 693 require.NoError(t, err) 694 695 walletInstance, err := New(sampleUserID, mockctx) 696 require.NotEmpty(t, walletInstance) 697 require.NoError(t, err) 698 699 result, err := walletInstance.Export("") 700 require.Empty(t, result) 701 require.Error(t, err) 702 require.EqualError(t, err, toBeImplementedErr) 703 } 704 705 func TestWallet_Import(t *testing.T) { 706 mockctx := newMockProvider(t) 707 err := CreateProfile(sampleUserID, mockctx, WithKeyServerURL(sampleKeyServerURL)) 708 require.NoError(t, err) 709 710 walletInstance, err := New(sampleUserID, mockctx) 711 require.NotEmpty(t, walletInstance) 712 require.NoError(t, err) 713 714 err = walletInstance.Import("", nil) 715 require.Error(t, err) 716 require.EqualError(t, err, toBeImplementedErr) 717 } 718 719 func TestWallet_Add(t *testing.T) { 720 mockctx := newMockProvider(t) 721 err := CreateProfile(sampleUserID, mockctx, WithKeyServerURL(sampleKeyServerURL)) 722 require.NoError(t, err) 723 724 walletInstance, err := New(sampleUserID, mockctx) 725 require.NotEmpty(t, walletInstance) 726 require.NoError(t, err) 727 728 // wallet locked 729 require.True(t, errors.Is(walletInstance.Add(sampleFakeTkn, Metadata, []byte(sampleContentValid)), ErrWalletLocked)) 730 731 // unlock wallet 732 tkn, err := walletInstance.Open(WithUnlockByAuthorizationToken(sampleRemoteKMSAuth)) 733 require.NoError(t, err) 734 735 // add data model to wallet 736 err = walletInstance.Add(tkn, Metadata, []byte(sampleContentValid)) 737 require.NoError(t, err) 738 } 739 740 func TestWallet_Get(t *testing.T) { 741 mockctx := newMockProvider(t) 742 user := uuid.New().String() 743 744 err := CreateProfile(user, mockctx, WithKeyServerURL(sampleKeyServerURL)) 745 require.NoError(t, err) 746 747 walletInstance, err := New(user, mockctx) 748 require.NotEmpty(t, walletInstance) 749 require.NoError(t, err) 750 751 tkn, err := walletInstance.Open(WithUnlockByAuthorizationToken(sampleRemoteKMSAuth)) 752 require.NoError(t, err) 753 754 err = walletInstance.Add(tkn, Metadata, []byte(sampleContentValid)) 755 require.NoError(t, err) 756 757 content, err := walletInstance.Get(tkn, Metadata, "did:example:123456789abcdefghi") 758 require.NoError(t, err) 759 require.NotEmpty(t, content) 760 require.Equal(t, sampleContentValid, string(content)) 761 } 762 763 func TestWallet_GetAll(t *testing.T) { 764 const vcContent = `{ 765 "@context": [ 766 "https://www.w3.org/2018/credentials/v1", 767 "https://www.w3.org/2018/credentials/examples/v1" 768 ], 769 "id": "%s", 770 "issuer": { 771 "id": "did:example:76e12ec712ebc6f1c221ebfeb1f" 772 }, 773 "type": [ 774 "VerifiableCredential", 775 "UniversityDegreeCredential" 776 ] 777 }` 778 779 const orgCollection = `{ 780 "@context": ["https://w3id.org/wallet/v1"], 781 "id": "did:example:acme123456789abcdefghi", 782 "type": "Organization", 783 "name": "Acme Corp.", 784 "image": "https://via.placeholder.com/150", 785 "description" : "A software company.", 786 "tags": ["professional", "organization"], 787 "correlation": ["4058a72a-9523-11ea-bb37-0242ac130002"] 788 }` 789 790 const collectionID = "did:example:acme123456789abcdefghi" 791 792 user := uuid.New().String() 793 794 mockctx := newMockProvider(t) 795 err := CreateProfile(user, mockctx, WithPassphrase(samplePassPhrase)) 796 require.NoError(t, err) 797 798 walletInstance, err := New(user, mockctx) 799 require.NotEmpty(t, walletInstance) 800 require.NoError(t, err) 801 802 tkn, err := walletInstance.Open(WithUnlockByPassphrase(samplePassPhrase)) 803 require.NoError(t, err) 804 805 const count = 5 806 807 var taggedKeys, untaggedKeys [count]string 808 809 // save test data without collection 810 for i := 0; i < count; i++ { 811 k := uuid.New().String() 812 813 require.NoError(t, walletInstance.Add(tkn, Credential, []byte(fmt.Sprintf(vcContent, k)))) 814 815 untaggedKeys[i] = k 816 } 817 818 // save a collection 819 require.NoError(t, walletInstance.Add(tkn, Collection, []byte(orgCollection))) 820 821 // save contents by collection 822 for i := 0; i < count; i++ { 823 k := uuid.New().String() 824 825 require.NoError(t, walletInstance.Add(tkn, Credential, []byte(fmt.Sprintf(vcContent, k)), 826 AddByCollection(collectionID))) 827 828 taggedKeys[i] = k 829 } 830 831 // get all by content 832 vcs, err := walletInstance.GetAll(tkn, Credential) 833 require.NoError(t, err) 834 require.Len(t, vcs, count*2) 835 836 // get all by content & collection 837 vcs, err = walletInstance.GetAll(tkn, Credential, FilterByCollection(collectionID)) 838 require.NoError(t, err) 839 require.Len(t, vcs, count) 840 841 // delete one item under collection 842 require.NoError(t, walletInstance.Remove(tkn, Credential, taggedKeys[0])) 843 // get all by content & collection 844 vcs, err = walletInstance.GetAll(tkn, Credential, FilterByCollection(collectionID)) 845 require.NoError(t, err) 846 require.Len(t, vcs, count-1) 847 848 // delete one item which is not under collection 849 require.NoError(t, walletInstance.Remove(tkn, Credential, untaggedKeys[0])) 850 // get all by content 851 vcs, err = walletInstance.GetAll(tkn, Credential) 852 require.NoError(t, err) 853 require.Len(t, vcs, count*2-2) 854 } 855 856 func TestWallet_Remove(t *testing.T) { 857 mockctx := newMockProvider(t) 858 user := uuid.New().String() 859 860 err := CreateProfile(user, mockctx, WithKeyServerURL(sampleKeyServerURL)) 861 require.NoError(t, err) 862 863 walletInstance, err := New(user, mockctx) 864 require.NotEmpty(t, walletInstance) 865 require.NoError(t, err) 866 867 tkn, err := walletInstance.Open(WithUnlockByAuthorizationToken(sampleRemoteKMSAuth)) 868 require.NoError(t, err) 869 870 err = walletInstance.Add(tkn, Metadata, []byte(sampleContentValid)) 871 require.NoError(t, err) 872 873 content, err := walletInstance.Get(tkn, Metadata, "did:example:123456789abcdefghi") 874 require.NoError(t, err) 875 require.NotEmpty(t, content) 876 877 err = walletInstance.Remove(tkn, Metadata, "did:example:123456789abcdefghi") 878 require.NoError(t, err) 879 880 content, err = walletInstance.Get(tkn, Metadata, "did:example:123456789abcdefghi") 881 require.Empty(t, content) 882 require.Error(t, err) 883 require.True(t, errors.Is(err, storage.ErrDataNotFound)) 884 } 885 886 func TestWallet_Query(t *testing.T) { 887 mockctx := newMockProvider(t) 888 user := uuid.New().String() 889 890 mockctx.VDRegistryValue = &mockvdr.MockVDRegistry{ 891 ResolveFunc: func(didID string, opts ...vdrapi.DIDMethodOption) (*did.DocResolution, error) { 892 if strings.HasPrefix(didID, "did:key:") { 893 k := key.New() 894 895 d, e := k.Read(didID) 896 if e != nil { 897 return nil, e 898 } 899 900 return d, nil 901 } 902 903 return nil, fmt.Errorf("did not found") 904 }, 905 } 906 907 err := CreateProfile(user, mockctx, WithKeyServerURL(sampleKeyServerURL)) 908 require.NoError(t, err) 909 910 vc1, err := (&verifiable.Credential{ 911 Context: []string{verifiable.ContextURI}, 912 Types: []string{verifiable.VCType}, 913 ID: "http://example.edu/credentials/9999", 914 CustomFields: map[string]interface{}{ 915 "first_name": "Jesse", 916 }, 917 Issued: &util.TimeWrapper{ 918 Time: time.Now(), 919 }, 920 Issuer: verifiable.Issuer{ 921 ID: "did:example:76e12ec712ebc6f1c221ebfeb1f", 922 }, 923 Subject: uuid.New().String(), 924 }).MarshalJSON() 925 require.NoError(t, err) 926 927 sampleVC := fmt.Sprintf(sampleVCFmt, verifiable.ContextURI) 928 vcForQuery := []byte(strings.ReplaceAll(sampleVC, 929 "http://example.edu/credentials/1872", "http://example.edu/credentials/1879")) 930 vcForDerive := []byte(sampleBBSVC) 931 932 walletInstance, err := New(user, mockctx) 933 require.NotEmpty(t, walletInstance) 934 require.NoError(t, err) 935 936 tkn, err := walletInstance.Open(WithUnlockByAuthorizationToken(sampleRemoteKMSAuth)) 937 require.NoError(t, err) 938 939 require.NoError(t, walletInstance.Add(tkn, Credential, vc1)) 940 require.NoError(t, walletInstance.Add(tkn, Credential, vcForQuery)) 941 require.NoError(t, walletInstance.Add(tkn, Credential, vcForDerive)) 942 943 pd := &presexch.PresentationDefinition{ 944 ID: uuid.New().String(), 945 InputDescriptors: []*presexch.InputDescriptor{{ 946 ID: uuid.New().String(), 947 Schema: []*presexch.Schema{{ 948 URI: fmt.Sprintf("%s#%s", verifiable.ContextID, verifiable.VCType), 949 }}, 950 Constraints: &presexch.Constraints{ 951 Fields: []*presexch.Field{{ 952 Path: []string{"$.first_name"}, 953 }}, 954 }, 955 }}, 956 } 957 958 // presentation exchange 959 pdJSON, err := json.Marshal(pd) 960 require.NoError(t, err) 961 require.NotEmpty(t, pdJSON) 962 963 // query by example 964 queryByExample := []byte(fmt.Sprintf(sampleQueryByExFmt, verifiable.ContextURI)) 965 // query by frame 966 queryByFrame := []byte(sampleQueryByFrame) 967 968 t.Run("test wallet queries", func(t *testing.T) { 969 tests := []struct { 970 name string 971 params []*QueryParams 972 resultCount int 973 vcCount map[int]int 974 error string 975 }{ 976 { 977 name: "query by presentation exchange - success", 978 params: []*QueryParams{ 979 {Type: "PresentationExchange", Query: []json.RawMessage{pdJSON}}, 980 }, 981 resultCount: 1, 982 vcCount: map[int]int{0: 1}, 983 }, 984 { 985 name: "query by example - success", 986 params: []*QueryParams{ 987 {Type: "QueryByExample", Query: []json.RawMessage{queryByExample}}, 988 }, 989 resultCount: 1, 990 vcCount: map[int]int{0: 1}, 991 }, 992 { 993 name: "query by frame - success", 994 params: []*QueryParams{ 995 {Type: "QueryByFrame", Query: []json.RawMessage{queryByFrame}}, 996 }, 997 resultCount: 1, 998 vcCount: map[int]int{0: 1}, 999 }, 1000 { 1001 name: "DIDAuth - success", 1002 params: []*QueryParams{ 1003 {Type: "DIDAuth"}, 1004 }, 1005 resultCount: 1, 1006 vcCount: map[int]int{0: 0}, 1007 }, 1008 { 1009 name: "multiple queries - success", 1010 params: []*QueryParams{ 1011 {Type: "PresentationExchange", Query: []json.RawMessage{pdJSON}}, 1012 {Type: "QueryByExample", Query: []json.RawMessage{queryByExample}}, 1013 {Type: "QueryByFrame", Query: []json.RawMessage{queryByFrame}}, 1014 }, 1015 resultCount: 2, 1016 vcCount: map[int]int{0: 1, 1: 2}, 1017 }, 1018 { 1019 name: "invalid query type", 1020 params: []*QueryParams{ 1021 {Type: "invalid"}, 1022 }, 1023 error: "unsupported query type", 1024 }, 1025 { 1026 name: "empty query type", 1027 params: []*QueryParams{}, 1028 error: "no result found", 1029 }, 1030 } 1031 1032 t.Parallel() 1033 1034 for _, test := range tests { 1035 tc := test 1036 t.Run(tc.name, func(t *testing.T) { 1037 results, err := walletInstance.Query(tkn, tc.params...) 1038 1039 if tc.error != "" { 1040 require.Empty(t, results) 1041 require.Error(t, err) 1042 require.Contains(t, err.Error(), tc.error) 1043 1044 return 1045 } 1046 1047 require.NoError(t, err) 1048 require.Len(t, results, tc.resultCount) 1049 1050 for i, result := range results { 1051 require.Len(t, result.Credentials(), tc.vcCount[i]) 1052 } 1053 }) 1054 } 1055 }) 1056 1057 t.Run("test get all error", func(t *testing.T) { 1058 user := uuid.New().String() 1059 mockctxInvalid := newMockProvider(t) 1060 1061 sp := getMockStorageProvider() 1062 1063 sp.MockStoreProvider.Store.ErrQuery = errors.New(sampleContenttErr) 1064 mockctxInvalid.StorageProviderValue = sp 1065 1066 err := CreateProfile(user, mockctxInvalid, WithKeyServerURL(sampleKeyServerURL)) 1067 require.NoError(t, err) 1068 1069 walletInstanceInvalid, err := New(user, mockctxInvalid) 1070 require.NoError(t, err) 1071 require.NotEmpty(t, walletInstanceInvalid) 1072 1073 result, err := walletInstanceInvalid.Query(sampleFakeTkn, &QueryParams{Type: "QueryByFrame"}) 1074 require.True(t, errors.Is(err, ErrWalletLocked)) 1075 require.Empty(t, result) 1076 1077 tk, err := walletInstanceInvalid.Open(WithUnlockByAuthorizationToken(sampleRemoteKMSAuth)) 1078 require.NoError(t, err) 1079 1080 result, err = walletInstanceInvalid.Query(tk, &QueryParams{Type: "QueryByFrame"}) 1081 require.Error(t, err) 1082 require.Contains(t, err.Error(), "failed to query credentials") 1083 require.Contains(t, err.Error(), sampleContenttErr) 1084 require.Empty(t, result) 1085 }) 1086 } 1087 1088 func TestWallet_Query_TwoInputDescriptorsWithTwoCredentialsWithOverlap(t *testing.T) { 1089 mockctx := newMockProvider(t) 1090 user := uuid.New().String() 1091 1092 err := CreateProfile(user, mockctx, WithKeyServerURL(sampleKeyServerURL)) 1093 require.NoError(t, err) 1094 1095 walletInstance, err := New(user, mockctx) 1096 require.NotEmpty(t, walletInstance) 1097 require.NoError(t, err) 1098 1099 tkn, err := walletInstance.Open(WithUnlockByAuthorizationToken(sampleRemoteKMSAuth)) 1100 require.NoError(t, err) 1101 1102 require.NoError(t, walletInstance.Add(tkn, Credential, []byte(testJSONLD))) 1103 require.NoError(t, walletInstance.Add(tkn, Credential, []byte(testSDJWT))) 1104 1105 var pd presexch.PresentationDefinition 1106 1107 err = json.Unmarshal([]byte(testPD), &pd) 1108 require.NoError(t, err) 1109 1110 vps, err := walletInstance.Query(tkn, &QueryParams{ 1111 Type: "PresentationExchange", 1112 Query: []json.RawMessage{[]byte(testPD)}, 1113 }) 1114 1115 require.NoError(t, err) 1116 1117 for _, vp := range vps { 1118 vpBytes, err := json.Marshal(vp) 1119 require.NoError(t, err) 1120 1121 require.False(t, strings.Contains(string(vpBytes), "[2]")) 1122 } 1123 } 1124 1125 func TestWallet_Issue(t *testing.T) { 1126 user := uuid.New().String() 1127 customVDR := &mockvdr.MockVDRegistry{ 1128 ResolveFunc: func(didID string, opts ...vdrapi.DIDMethodOption) (*did.DocResolution, error) { 1129 if didID == sampleInvalidDIDID { 1130 d, e := did.ParseDocument(testdata.SampleInvalidDID) 1131 require.NoError(t, e) 1132 1133 return &did.DocResolution{DIDDocument: d}, nil 1134 } else if strings.HasPrefix(didID, "did:key:") { 1135 k := key.New() 1136 1137 d, e := k.Read(didID) 1138 if e != nil { 1139 return nil, e 1140 } 1141 1142 return d, nil 1143 } 1144 1145 return nil, fmt.Errorf("did not found") 1146 }, 1147 } 1148 1149 mockctx := newMockProvider(t) 1150 mockctx.VDRegistryValue = customVDR 1151 mockctx.CryptoValue = &cryptomock.Crypto{} 1152 1153 err := CreateProfile(user, mockctx, WithPassphrase(samplePassPhrase)) 1154 require.NoError(t, err) 1155 1156 t.Run("Test VC wallet issue using controller - success", func(t *testing.T) { 1157 walletInstance, err := New(user, mockctx) 1158 require.NotEmpty(t, walletInstance) 1159 require.NoError(t, err) 1160 1161 // unlock wallet 1162 authToken, err := walletInstance.Open(WithUnlockByPassphrase(samplePassPhrase)) 1163 require.NoError(t, err) 1164 require.NotEmpty(t, authToken) 1165 1166 defer walletInstance.Close() 1167 1168 // import keys manually 1169 session, err := sessionManager().getSession(authToken) 1170 require.NotEmpty(t, session) 1171 require.NoError(t, err) 1172 1173 kmgr := session.KeyManager 1174 require.NotEmpty(t, kmgr) 1175 1176 edPriv := ed25519.PrivateKey(base58.Decode(pkBase58)) 1177 // nolint: errcheck, gosec 1178 kmgr.ImportPrivateKey(edPriv, kms.ED25519, kms.WithKeyID(kid)) 1179 1180 // sign with just controller 1181 result, err := walletInstance.Issue(authToken, testdata.SampleUDCVC, &ProofOptions{ 1182 Controller: didKey, 1183 }) 1184 require.NoError(t, err) 1185 require.NotEmpty(t, result) 1186 require.Len(t, result.Proofs, 1) 1187 }) 1188 1189 t.Run("Test VC wallet issue JSONWebSignature2020 using controller - success", func(t *testing.T) { 1190 walletInstance, err := New(user, mockctx) 1191 require.NotEmpty(t, walletInstance) 1192 require.NoError(t, err) 1193 1194 // unlock wallet 1195 authToken, err := walletInstance.Open(WithUnlockByPassphrase(samplePassPhrase)) 1196 require.NoError(t, err) 1197 require.NotEmpty(t, authToken) 1198 1199 defer walletInstance.Close() 1200 1201 // import keys manually 1202 session, err := sessionManager().getSession(authToken) 1203 require.NotEmpty(t, session) 1204 require.NoError(t, err) 1205 edPriv := ed25519.PrivateKey(base58.Decode(pkBase58)) 1206 // nolint: errcheck, gosec 1207 session.KeyManager.ImportPrivateKey(edPriv, kms.ED25519, kms.WithKeyID(kid)) 1208 1209 // sign with just controller 1210 result, err := walletInstance.Issue(authToken, testdata.SampleUDCVC, &ProofOptions{ 1211 Controller: didKey, 1212 ProofType: JSONWebSignature2020, 1213 }) 1214 require.NoError(t, err) 1215 require.NotEmpty(t, result) 1216 require.Len(t, result.Proofs, 1) 1217 }) 1218 1219 t.Run("Test VC wallet issue JWT VC using controller - success", func(t *testing.T) { 1220 walletInstance, err := New(user, mockctx) 1221 require.NotEmpty(t, walletInstance) 1222 require.NoError(t, err) 1223 1224 walletInstance.walletCrypto = &cryptomock.Crypto{ 1225 SignValue: []byte("abcdefg"), 1226 } 1227 1228 // unlock wallet 1229 authToken, err := walletInstance.Open(WithUnlockByPassphrase(samplePassPhrase)) 1230 require.NoError(t, err) 1231 require.NotEmpty(t, authToken) 1232 1233 defer walletInstance.Close() 1234 1235 // import keys manually 1236 session, err := sessionManager().getSession(authToken) 1237 require.NotEmpty(t, session) 1238 require.NoError(t, err) 1239 edPriv := ed25519.PrivateKey(base58.Decode(pkBase58)) 1240 // nolint: errcheck, gosec 1241 session.KeyManager.ImportPrivateKey(edPriv, kms.ED25519, kms.WithKeyID(kid)) 1242 1243 // sign with just controller 1244 result, err := walletInstance.Issue(authToken, testdata.SampleUDCVC, &ProofOptions{ 1245 Controller: didKey, 1246 ProofFormat: ExternalJWTProofFormat, 1247 ProofType: JSONWebSignature2020, 1248 }) 1249 require.NoError(t, err) 1250 require.NotEmpty(t, result) 1251 1252 require.NotEqual(t, "", result.JWT) 1253 1254 vcExpected, err := verifiable.ParseCredential(testdata.SampleUDCVC, verifiable.WithDisabledProofCheck(), 1255 verifiable.WithJSONLDDocumentLoader(walletInstance.jsonldDocumentLoader)) 1256 require.NoError(t, err) 1257 1258 vcActual, err := verifiable.ParseCredential([]byte(result.JWT), verifiable.WithDisabledProofCheck(), 1259 verifiable.WithJSONLDDocumentLoader(walletInstance.jsonldDocumentLoader)) 1260 require.NoError(t, err) 1261 1262 require.Equal(t, result.JWT, vcActual.JWT) 1263 vcActual.JWT = "" 1264 1265 require.Equal(t, vcExpected, vcActual) 1266 }) 1267 1268 t.Run("Test VC wallet issue JWT VC - fail to generate claims", func(t *testing.T) { 1269 walletInstance, err := New(user, mockctx) 1270 require.NotEmpty(t, walletInstance) 1271 require.NoError(t, err) 1272 1273 walletInstance.walletCrypto = &cryptomock.Crypto{ 1274 SignValue: []byte("abcdefg"), 1275 } 1276 1277 // unlock wallet 1278 authToken, err := walletInstance.Open(WithUnlockByPassphrase(samplePassPhrase)) 1279 require.NoError(t, err) 1280 require.NotEmpty(t, authToken) 1281 1282 defer walletInstance.Close() 1283 1284 // import keys manually 1285 session, err := sessionManager().getSession(authToken) 1286 require.NotEmpty(t, session) 1287 require.NoError(t, err) 1288 edPriv := ed25519.PrivateKey(base58.Decode(pkBase58)) 1289 // nolint: errcheck, gosec 1290 session.KeyManager.ImportPrivateKey(edPriv, kms.ED25519, kms.WithKeyID(kid)) 1291 1292 minimalVC := &verifiable.Credential{ 1293 Context: []string{verifiable.ContextURI}, 1294 ID: "https://foo.bar", 1295 Issued: util.NewTime(time.Now()), 1296 Types: []string{verifiable.VCType}, 1297 Subject: []verifiable.Subject{ 1298 { 1299 ID: "foo", // with multiple subjects, VC can't be converted to JWT claims. 1300 }, 1301 { 1302 ID: "bar", 1303 }, 1304 }, 1305 Issuer: verifiable.Issuer{ 1306 ID: "https://bar.baz", 1307 }, 1308 } 1309 1310 vcBytes, err := minimalVC.MarshalJSON() 1311 require.NoError(t, err) 1312 1313 // sign with just controller 1314 _, err = walletInstance.Issue(authToken, vcBytes, &ProofOptions{ 1315 Controller: didKey, 1316 ProofFormat: ExternalJWTProofFormat, 1317 ProofType: JSONWebSignature2020, 1318 }) 1319 require.Error(t, err) 1320 require.Contains(t, err.Error(), "failed to generate JWT claims for VC") 1321 }) 1322 1323 t.Run("Test VC wallet issue JWT VC - fail to create JWT", func(t *testing.T) { 1324 walletInstance, err := New(user, mockctx) 1325 require.NotEmpty(t, walletInstance) 1326 require.NoError(t, err) 1327 1328 expectErr := errors.New("expected error") 1329 1330 walletInstance.walletCrypto = &cryptomock.Crypto{ 1331 SignErr: expectErr, 1332 } 1333 1334 // unlock wallet 1335 authToken, err := walletInstance.Open(WithUnlockByPassphrase(samplePassPhrase)) 1336 require.NoError(t, err) 1337 require.NotEmpty(t, authToken) 1338 1339 defer walletInstance.Close() 1340 1341 // import keys manually 1342 session, err := sessionManager().getSession(authToken) 1343 require.NotEmpty(t, session) 1344 require.NoError(t, err) 1345 edPriv := ed25519.PrivateKey(base58.Decode(pkBase58)) 1346 // nolint: errcheck, gosec 1347 session.KeyManager.ImportPrivateKey(edPriv, kms.ED25519, kms.WithKeyID(kid)) 1348 1349 _, err = walletInstance.Issue(authToken, testdata.SampleUDCVC, &ProofOptions{ 1350 Controller: didKey, 1351 ProofFormat: ExternalJWTProofFormat, 1352 ProofType: JSONWebSignature2020, 1353 }) 1354 require.Error(t, err) 1355 require.ErrorIs(t, err, expectErr) 1356 require.Contains(t, err.Error(), "failed to generate JWT VC") 1357 }) 1358 1359 t.Run("Test VC wallet issue using verification method - success", func(t *testing.T) { 1360 walletInstance, err := New(user, mockctx) 1361 require.NotEmpty(t, walletInstance) 1362 require.NoError(t, err) 1363 1364 // unlock wallet 1365 authToken, err := walletInstance.Open(WithUnlockByPassphrase(samplePassPhrase)) 1366 require.NoError(t, err) 1367 require.NotEmpty(t, authToken) 1368 1369 defer walletInstance.Close() 1370 1371 // import keys manually 1372 session, err := sessionManager().getSession(authToken) 1373 require.NotEmpty(t, session) 1374 require.NoError(t, err) 1375 1376 edPriv := ed25519.PrivateKey(base58.Decode(pkBase58)) 1377 // nolint: errcheck, gosec 1378 session.KeyManager.ImportPrivateKey(edPriv, kms.ED25519, kms.WithKeyID(kid)) 1379 1380 // issue 1381 result, err := walletInstance.Issue(authToken, testdata.SampleUDCVC, &ProofOptions{ 1382 Controller: didKey, 1383 VerificationMethod: sampleVerificationMethod, 1384 }) 1385 require.NoError(t, err) 1386 require.NotEmpty(t, result) 1387 require.Len(t, result.Proofs, 1) 1388 }) 1389 1390 t.Run("Test VC wallet issue using all options - success", func(t *testing.T) { 1391 walletInstance, err := New(user, mockctx) 1392 require.NotEmpty(t, walletInstance) 1393 require.NoError(t, err) 1394 1395 // unlock wallet 1396 authToken, err := walletInstance.Open(WithUnlockByPassphrase(samplePassPhrase)) 1397 require.NoError(t, err) 1398 require.NotEmpty(t, authToken) 1399 1400 defer walletInstance.Close() 1401 1402 // import keys manually 1403 session, err := sessionManager().getSession(authToken) 1404 require.NotEmpty(t, session) 1405 require.NoError(t, err) 1406 1407 kmgr := session.KeyManager 1408 require.NotEmpty(t, kmgr) 1409 1410 edPriv := ed25519.PrivateKey(base58.Decode(pkBase58)) 1411 // nolint: errcheck, gosec 1412 kmgr.ImportPrivateKey(edPriv, kms.ED25519, kms.WithKeyID(kid)) 1413 1414 // issue credential 1415 proofRepr := verifiable.SignatureJWS 1416 vm := sampleVerificationMethod 1417 created, err := time.Parse("2006-01-02", sampleCreatedDate) 1418 require.NoError(t, err) 1419 1420 result, err := walletInstance.Issue(authToken, testdata.SampleUDCVC, &ProofOptions{ 1421 Controller: didKey, 1422 VerificationMethod: vm, 1423 ProofType: JSONWebSignature2020, 1424 Challenge: sampleChallenge, 1425 Domain: sampleDomain, 1426 Created: &created, 1427 ProofRepresentation: &proofRepr, 1428 }) 1429 require.NoError(t, err) 1430 require.NotEmpty(t, result) 1431 require.Len(t, result.Proofs, 1) 1432 1433 require.Equal(t, result.Proofs[0]["challenge"], sampleChallenge) 1434 require.Equal(t, result.Proofs[0]["created"], "2020-12-25T00:00:00Z") 1435 require.Equal(t, result.Proofs[0]["domain"], sampleDomain) 1436 require.NotEmpty(t, result.Proofs[0]["jws"]) 1437 require.Equal(t, result.Proofs[0]["proofPurpose"], "assertionMethod") 1438 require.Equal(t, result.Proofs[0]["type"], JSONWebSignature2020) 1439 require.Equal(t, result.Proofs[0]["verificationMethod"], vm) 1440 }) 1441 1442 t.Run("Test VC wallet issue using BBS - success", func(t *testing.T) { 1443 walletInstance, err := New(user, mockctx) 1444 require.NotEmpty(t, walletInstance) 1445 require.NoError(t, err) 1446 1447 // unlock wallet 1448 authToken, err := walletInstance.Open(WithUnlockByPassphrase(samplePassPhrase)) 1449 require.NoError(t, err) 1450 require.NotEmpty(t, authToken) 1451 1452 defer walletInstance.Close() 1453 1454 // import keys manually 1455 session, err := sessionManager().getSession(authToken) 1456 require.NotEmpty(t, session) 1457 require.NoError(t, err) 1458 1459 kmgr := session.KeyManager 1460 require.NotEmpty(t, kmgr) 1461 1462 privKeyBBS, err := bbs12381g2pub.UnmarshalPrivateKey(base58.Decode(pkBBSBase58)) 1463 require.NoError(t, err) 1464 // nolint: errcheck, gosec 1465 kmgr.ImportPrivateKey(privKeyBBS, kms.BLS12381G2Type, kms.WithKeyID(keyIDBBS)) 1466 1467 // sign with just controller 1468 proofRepr := verifiable.SignatureProofValue 1469 result, err := walletInstance.Issue(authToken, testdata.SampleUDCVC, &ProofOptions{ 1470 Controller: didKeyBBS, 1471 ProofType: BbsBlsSignature2020, 1472 ProofRepresentation: &proofRepr, 1473 }) 1474 require.NoError(t, err) 1475 require.NotEmpty(t, result) 1476 require.Len(t, result.Proofs, 1) 1477 }) 1478 1479 t.Run("Test VC wallet issue using stored DID - success", func(t *testing.T) { 1480 mockctx1 := newMockProvider(t) 1481 mockctx1.VDRegistryValue = &mockvdr.MockVDRegistry{} 1482 mockctx1.CryptoValue = &cryptomock.Crypto{} 1483 1484 err := CreateProfile(user, mockctx1, WithPassphrase(samplePassPhrase)) 1485 require.NoError(t, err) 1486 1487 walletInstance, err := New(user, mockctx1) 1488 require.NotEmpty(t, walletInstance) 1489 require.NoError(t, err) 1490 1491 // unlock wallet 1492 authToken, err := walletInstance.Open(WithUnlockByPassphrase(samplePassPhrase)) 1493 require.NoError(t, err) 1494 require.NotEmpty(t, authToken) 1495 1496 defer walletInstance.Close() 1497 1498 // import keys manually 1499 session, err := sessionManager().getSession(authToken) 1500 require.NotEmpty(t, session) 1501 require.NoError(t, err) 1502 1503 kmgr := session.KeyManager 1504 require.NotEmpty(t, kmgr) 1505 1506 edPriv := ed25519.PrivateKey(base58.Decode(pkBase58)) 1507 // nolint: errcheck, gosec 1508 kmgr.ImportPrivateKey(edPriv, kms.ED25519, kms.WithKeyID(kid)) 1509 1510 // save DID Resolution response 1511 err = walletInstance.Add(authToken, DIDResolutionResponse, testdata.SampleDocResolutionResponse) 1512 require.NoError(t, err) 1513 1514 // sign with just controller 1515 result, err := walletInstance.Issue(authToken, testdata.SampleUDCVC, &ProofOptions{ 1516 Controller: didKey, 1517 }) 1518 require.NoError(t, err) 1519 require.NotEmpty(t, result) 1520 require.Len(t, result.Proofs, 1) 1521 }) 1522 1523 t.Run("Test VC wallet issue failure - invalid VC", func(t *testing.T) { 1524 walletInstance, err := New(user, mockctx) 1525 require.NotEmpty(t, walletInstance) 1526 require.NoError(t, err) 1527 1528 result, err := walletInstance.Issue(sampleFakeTkn, []byte("--"), &ProofOptions{}) 1529 require.Empty(t, result) 1530 require.Error(t, err) 1531 require.Contains(t, err.Error(), "failed to parse credential") 1532 }) 1533 1534 t.Run("Test VC wallet issue failure - proof option validation", func(t *testing.T) { 1535 walletInstance, err := New(user, mockctx) 1536 require.NotEmpty(t, walletInstance) 1537 require.NoError(t, err) 1538 1539 // unlock wallet 1540 authToken, err := walletInstance.Open(WithUnlockByPassphrase(samplePassPhrase)) 1541 require.NoError(t, err) 1542 require.NotEmpty(t, authToken) 1543 1544 defer walletInstance.Close() 1545 1546 // no controller 1547 result, err := walletInstance.Issue(authToken, testdata.SampleUDCVC, &ProofOptions{}) 1548 require.Empty(t, result) 1549 require.Error(t, err) 1550 require.Contains(t, err.Error(), "invalid proof option, 'controller' is required") 1551 1552 // DID not found 1553 result, err = walletInstance.Issue(authToken, testdata.SampleUDCVC, &ProofOptions{ 1554 Controller: "did:example:1234", 1555 }) 1556 require.Empty(t, result) 1557 require.Error(t, err) 1558 require.Contains(t, err.Error(), "failed to prepare proof: did not found") 1559 1560 // no assertion method 1561 result, err = walletInstance.Issue(authToken, testdata.SampleUDCVC, &ProofOptions{ 1562 Controller: sampleInvalidDIDID, 1563 }) 1564 require.Empty(t, result) 1565 require.Error(t, err) 1566 require.Contains(t, err.Error(), "unable to find 'assertionMethod' for given verification method") 1567 }) 1568 1569 t.Run("Test VC wallet issue failure - add proof errors", func(t *testing.T) { 1570 walletInstance, err := New(user, mockctx) 1571 require.NotEmpty(t, walletInstance) 1572 require.NoError(t, err) 1573 1574 // wallet locked 1575 result, err := walletInstance.Issue(sampleFakeTkn, testdata.SampleUDCVC, &ProofOptions{ 1576 Controller: didKey, 1577 }) 1578 require.Empty(t, result) 1579 require.Error(t, err) 1580 require.Contains(t, err.Error(), "wallet locked") 1581 1582 // get token 1583 authToken, err := walletInstance.Open(WithUnlockByPassphrase(samplePassPhrase)) 1584 require.NoError(t, err) 1585 require.NotEmpty(t, authToken) 1586 1587 defer walletInstance.Close() 1588 1589 // key not found 1590 result, err = walletInstance.Issue(authToken, testdata.SampleUDCVC, &ProofOptions{ 1591 Controller: "did:key:z6MkjRagNiMu91DduvCvgEsqLZDVzrJzFrwahc4tXLt9DoHd", 1592 }) 1593 require.Empty(t, result) 1594 require.Contains(t, err.Error(), "cannot read data for keysetID") 1595 1596 // import keys manually 1597 session, err := sessionManager().getSession(authToken) 1598 require.NotEmpty(t, session) 1599 require.NoError(t, err) 1600 1601 kmgr := session.KeyManager 1602 require.NotEmpty(t, kmgr) 1603 1604 edPriv := ed25519.PrivateKey(base58.Decode(pkBase58)) 1605 // nolint: errcheck, gosec 1606 kmgr.ImportPrivateKey(edPriv, kms.ED25519, kms.WithKeyID(kid)) 1607 1608 // invalid signature type 1609 result, err = walletInstance.Issue(authToken, testdata.SampleUDCVC, &ProofOptions{ 1610 Controller: didKey, 1611 ProofType: "invalid", 1612 }) 1613 require.Empty(t, result) 1614 require.Contains(t, err.Error(), " unsupported signature type 'invalid'") 1615 1616 // wrong key type 1617 result, err = walletInstance.Issue(authToken, testdata.SampleUDCVC, &ProofOptions{ 1618 Controller: didKey, 1619 ProofType: BbsBlsSignature2020, 1620 }) 1621 require.Empty(t, result) 1622 require.Contains(t, err.Error(), "failed to add linked data proof") 1623 }) 1624 } 1625 1626 func TestWallet_Prove(t *testing.T) { 1627 user := uuid.New().String() 1628 customVDR := &mockvdr.MockVDRegistry{ 1629 ResolveFunc: func(didID string, opts ...vdrapi.DIDMethodOption) (*did.DocResolution, error) { 1630 if didID == sampleInvalidDIDID { 1631 d, e := did.ParseDocument(testdata.SampleInvalidDID) 1632 require.NoError(t, e) 1633 1634 return &did.DocResolution{DIDDocument: d}, nil 1635 } else if strings.HasPrefix(didID, "did:key:") { 1636 k := key.New() 1637 1638 d, e := k.Read(didID) 1639 if e != nil { 1640 return nil, e 1641 } 1642 1643 return d, nil 1644 } 1645 1646 return nil, fmt.Errorf("did not found") 1647 }, 1648 } 1649 1650 mockctx := newMockProvider(t) 1651 mockctx.VDRegistryValue = customVDR 1652 mockctx.CryptoValue = &cryptomock.Crypto{ 1653 SignValue: []byte("abcdefg"), 1654 } 1655 1656 // create profile 1657 err := CreateProfile(user, mockctx, WithPassphrase(samplePassPhrase)) 1658 require.NoError(t, err) 1659 1660 // prepare VCs for tests 1661 vcs := make(map[string]*verifiable.Credential, 2) 1662 walletForIssue, err := New(user, mockctx) 1663 require.NotEmpty(t, walletForIssue) 1664 require.NoError(t, err) 1665 1666 issuerToken, err := walletForIssue.Open(WithUnlockByPassphrase(samplePassPhrase)) 1667 require.NoError(t, err) 1668 require.NotEmpty(t, issuerToken) 1669 1670 // import ED25519 & BLS12381G2Type keys manually 1671 session, err := sessionManager().getSession(issuerToken) 1672 require.NotEmpty(t, session) 1673 require.NoError(t, err) 1674 1675 kmgr := session.KeyManager 1676 require.NotEmpty(t, kmgr) 1677 1678 edPriv := ed25519.PrivateKey(base58.Decode(pkBase58)) 1679 // nolint: errcheck, gosec 1680 kmgr.ImportPrivateKey(edPriv, kms.ED25519, kms.WithKeyID(kid)) 1681 1682 privKeyBBS, err := bbs12381g2pub.UnmarshalPrivateKey(base58.Decode(pkBBSBase58)) 1683 require.NoError(t, err) 1684 // nolint: errcheck, gosec 1685 kmgr.ImportPrivateKey(privKeyBBS, kms.BLS12381G2Type, kms.WithKeyID(keyIDBBS)) 1686 1687 // issue a credential with Ed25519Signature2018 1688 result, err := walletForIssue.Issue(issuerToken, testdata.SampleUDCVC, &ProofOptions{ 1689 Controller: didKey, 1690 }) 1691 require.NoError(t, err) 1692 require.NotEmpty(t, result) 1693 require.Len(t, result.Proofs, 1) 1694 vcs["edvc"] = result 1695 1696 // issue a credential with BbsBlsSignature2020 1697 proofRepr := verifiable.SignatureProofValue 1698 result, err = walletForIssue.Issue(issuerToken, testdata.SampleUDCVC, &ProofOptions{ 1699 Controller: didKeyBBS, 1700 ProofType: BbsBlsSignature2020, 1701 ProofRepresentation: &proofRepr, 1702 }) 1703 require.NoError(t, err) 1704 require.NotEmpty(t, result) 1705 require.Len(t, result.Proofs, 1) 1706 vcs["bbsvc"] = result 1707 1708 templateCred, err := verifiable.ParseCredential(testdata.SampleUDCVC, verifiable.WithDisabledProofCheck(), 1709 verifiable.WithJSONLDDocumentLoader(walletForIssue.jsonldDocumentLoader)) 1710 require.NoError(t, err) 1711 1712 templateCred.Issuer.ID = didKey 1713 1714 templateData, err := templateCred.MarshalJSON() 1715 require.NoError(t, err) 1716 1717 // issue a JWT credential 1718 result, err = walletForIssue.Issue(issuerToken, templateData, &ProofOptions{ 1719 Controller: didKey, 1720 VerificationMethod: sampleVerificationMethod, 1721 ProofFormat: ExternalJWTProofFormat, 1722 }) 1723 require.NoError(t, err) 1724 require.NotEmpty(t, result) 1725 require.NotEqual(t, "", result.JWT) 1726 require.True(t, jwt.IsJWS(result.JWT)) 1727 1728 vcs["jwtvc"] = result 1729 1730 walletForIssue.Close() 1731 1732 t.Run("Test prove using stored & raw credential - success", func(t *testing.T) { 1733 walletInstance, err := New(user, mockctx) 1734 require.NotEmpty(t, walletInstance) 1735 require.NoError(t, err) 1736 1737 // unlock wallet 1738 authToken, err := walletInstance.Open(WithUnlockByPassphrase(samplePassPhrase)) 1739 require.NoError(t, err) 1740 require.NotEmpty(t, authToken) 1741 1742 defer walletInstance.Close() 1743 1744 // save one VC in store 1745 cleanup := addCredentialsToWallet(t, walletInstance, authToken, vcs["edvc"]) 1746 defer cleanup() 1747 1748 // import keys manually for signing presentation 1749 session, err := sessionManager().getSession(authToken) 1750 require.NotEmpty(t, session) 1751 require.NoError(t, err) 1752 1753 kmgr := session.KeyManager 1754 require.NotEmpty(t, kmgr) 1755 1756 edPriv := ed25519.PrivateKey(base58.Decode(pkBase58)) 1757 // nolint: errcheck, gosec 1758 kmgr.ImportPrivateKey(edPriv, kms.ED25519, kms.WithKeyID(kid)) 1759 1760 edVCBytes, err := json.Marshal(vcs["edvc"]) 1761 require.NoError(t, err) 1762 1763 bbsVCBytes, err := json.Marshal(vcs["bbsvc"]) 1764 require.NoError(t, err) 1765 1766 jwtVCBytes, err := json.Marshal(vcs["jwtvc"]) 1767 require.NoError(t, err) 1768 1769 // sign with just controller (one stored & one raw bytes) 1770 result, err := walletInstance.Prove(authToken, 1771 &ProofOptions{Controller: didKey}, 1772 WithStoredCredentialsToProve(vcs["edvc"].ID), 1773 WithRawCredentialsToProve(bbsVCBytes, jwtVCBytes), 1774 WithCredentialsToProve(vcs["edvc"]), 1775 ) 1776 require.NoError(t, err) 1777 require.NotEmpty(t, result) 1778 require.Len(t, result.Proofs, 1) 1779 require.Len(t, result.Credentials(), 4) 1780 require.Equal(t, result.Holder, didKey) 1781 1782 // sign with just controller with all raw credentials 1783 result, err = walletInstance.Prove(authToken, 1784 &ProofOptions{Controller: didKey}, 1785 WithRawCredentialsToProve(edVCBytes, bbsVCBytes, jwtVCBytes), 1786 ) 1787 require.NoError(t, err) 1788 require.NotEmpty(t, result) 1789 require.Len(t, result.Proofs, 1) 1790 require.Equal(t, result.Holder, didKey) 1791 }) 1792 1793 t.Run("Test prove using presentation - success", func(t *testing.T) { 1794 walletInstance, err := New(user, mockctx) 1795 require.NotEmpty(t, walletInstance) 1796 require.NoError(t, err) 1797 1798 // unlock wallet 1799 authToken, err := walletInstance.Open(WithUnlockByPassphrase(samplePassPhrase)) 1800 require.NoError(t, err) 1801 require.NotEmpty(t, authToken) 1802 1803 defer walletInstance.Close() 1804 1805 // save one VC in store 1806 cleanup := addCredentialsToWallet(t, walletInstance, authToken, vcs["edvc"]) 1807 defer cleanup() 1808 1809 // import keys manually for signing presentation 1810 session, err := sessionManager().getSession(authToken) 1811 require.NotEmpty(t, session) 1812 require.NoError(t, err) 1813 1814 kmgr := session.KeyManager 1815 require.NotEmpty(t, kmgr) 1816 1817 edPriv := ed25519.PrivateKey(base58.Decode(pkBase58)) 1818 // nolint: errcheck, gosec 1819 kmgr.ImportPrivateKey(edPriv, kms.ED25519, kms.WithKeyID(kid)) 1820 1821 bbsVCBytes, err := json.Marshal(vcs["bbsvc"]) 1822 require.NoError(t, err) 1823 1824 pres, err := verifiable.NewPresentation(verifiable.WithCredentials(vcs["edvc"])) 1825 require.NoError(t, err) 1826 require.NotEmpty(t, pres) 1827 1828 // sign with just controller 1829 result, err := walletInstance.Prove(authToken, 1830 &ProofOptions{Controller: didKey}, 1831 WithPresentationToProve(pres), 1832 ) 1833 require.NoError(t, err) 1834 require.NotEmpty(t, result) 1835 require.Len(t, result.Proofs, 1) 1836 require.Len(t, result.Credentials(), 1) 1837 require.Equal(t, result.Holder, didKey) 1838 1839 // sign with just controller (sign with presentation & credentials) 1840 pres, err = verifiable.NewPresentation(verifiable.WithCredentials(vcs["edvc"])) 1841 require.NoError(t, err) 1842 require.NotEmpty(t, pres) 1843 1844 result, err = walletInstance.Prove(authToken, 1845 &ProofOptions{Controller: didKey}, 1846 WithPresentationToProve(pres), 1847 WithStoredCredentialsToProve(vcs["edvc"].ID), 1848 WithRawCredentialsToProve(bbsVCBytes), 1849 ) 1850 1851 require.NoError(t, err) 1852 require.NotEmpty(t, result) 1853 require.Len(t, result.Proofs, 1) 1854 require.Len(t, result.Credentials(), 3) 1855 require.Equal(t, result.Holder, didKey) 1856 }) 1857 1858 t.Run("Test prove using raw presentation - success", func(t *testing.T) { 1859 walletInstance, err := New(user, mockctx) 1860 require.NotEmpty(t, walletInstance) 1861 require.NoError(t, err) 1862 1863 // unlock wallet 1864 authToken, err := walletInstance.Open(WithUnlockByPassphrase(samplePassPhrase)) 1865 require.NoError(t, err) 1866 require.NotEmpty(t, authToken) 1867 1868 defer walletInstance.Close() 1869 1870 // save one VC in store 1871 cleanup := addCredentialsToWallet(t, walletInstance, authToken, vcs["edvc"]) 1872 defer cleanup() 1873 1874 // import keys manually for signing presentation 1875 session, err := sessionManager().getSession(authToken) 1876 require.NotEmpty(t, session) 1877 require.NoError(t, err) 1878 1879 kmgr := session.KeyManager 1880 require.NotEmpty(t, kmgr) 1881 1882 edPriv := ed25519.PrivateKey(base58.Decode(pkBase58)) 1883 // nolint: errcheck, gosec 1884 kmgr.ImportPrivateKey(edPriv, kms.ED25519, kms.WithKeyID(kid)) 1885 1886 bbsVCBytes, err := json.Marshal(vcs["bbsvc"]) 1887 require.NoError(t, err) 1888 1889 pres, err := verifiable.NewPresentation(verifiable.WithCredentials(vcs["edvc"])) 1890 require.NoError(t, err) 1891 require.NotEmpty(t, pres) 1892 1893 // sign with just controller 1894 result, err := walletInstance.Prove(authToken, 1895 &ProofOptions{Controller: didKey}, 1896 WithPresentationToProve(pres), 1897 ) 1898 require.NoError(t, err) 1899 require.NotEmpty(t, result) 1900 require.Len(t, result.Proofs, 1) 1901 require.Len(t, result.Credentials(), 1) 1902 require.Equal(t, result.Holder, didKey) 1903 1904 // sign with just controller (sign with presentation & credentials) 1905 pres, err = verifiable.NewPresentation(verifiable.WithCredentials(vcs["edvc"])) 1906 require.NoError(t, err) 1907 require.NotEmpty(t, pres) 1908 1909 rawPres, err := pres.MarshalJSON() 1910 require.NoError(t, err) 1911 1912 result, err = walletInstance.Prove(authToken, 1913 &ProofOptions{Controller: didKey}, 1914 WithRawPresentationToProve(rawPres), 1915 WithStoredCredentialsToProve(vcs["edvc"].ID), 1916 WithRawCredentialsToProve(bbsVCBytes), 1917 ) 1918 1919 require.NoError(t, err) 1920 require.NotEmpty(t, result) 1921 require.Len(t, result.Proofs, 1) 1922 require.Len(t, result.Credentials(), 3) 1923 require.Equal(t, result.Holder, didKey) 1924 }) 1925 1926 t.Run("Test prove using various proof options - success", func(t *testing.T) { 1927 walletInstance, err := New(user, mockctx) 1928 require.NotEmpty(t, walletInstance) 1929 require.NoError(t, err) 1930 1931 // unlock wallet 1932 authToken, err := walletInstance.Open(WithUnlockByPassphrase(samplePassPhrase)) 1933 require.NoError(t, err) 1934 require.NotEmpty(t, authToken) 1935 1936 defer walletInstance.Close() 1937 1938 // save all VCs in store 1939 cleanup := addCredentialsToWallet(t, walletInstance, authToken, vcs["edvc"], vcs["bbsvc"]) 1940 defer cleanup() 1941 1942 // import keys manually for signing presentation 1943 session, err := sessionManager().getSession(authToken) 1944 require.NotEmpty(t, session) 1945 require.NoError(t, err) 1946 1947 kmgr := session.KeyManager 1948 require.NotEmpty(t, kmgr) 1949 1950 edPriv := ed25519.PrivateKey(base58.Decode(pkBase58)) 1951 // nolint: errcheck, gosec 1952 kmgr.ImportPrivateKey(edPriv, kms.ED25519, kms.WithKeyID(kid)) 1953 1954 // prepare opts 1955 proofRepr := verifiable.SignatureJWS 1956 vm := sampleVerificationMethod 1957 created, err := time.Parse("2006-01-02", sampleCreatedDate) 1958 require.NoError(t, err) 1959 1960 // sign with just controller (one stored & one raw) 1961 result, err := walletInstance.Prove(authToken, &ProofOptions{ 1962 Controller: didKey, 1963 VerificationMethod: vm, 1964 ProofType: JSONWebSignature2020, 1965 Challenge: sampleChallenge, 1966 Domain: sampleDomain, 1967 Created: &created, 1968 ProofRepresentation: &proofRepr, 1969 }, WithStoredCredentialsToProve(vcs["edvc"].ID, vcs["bbsvc"].ID)) 1970 require.NoError(t, err) 1971 require.NotEmpty(t, result) 1972 require.Len(t, result.Proofs, 1) 1973 1974 require.Equal(t, result.Proofs[0]["challenge"], sampleChallenge) 1975 require.Equal(t, result.Proofs[0]["created"], "2020-12-25T00:00:00Z") 1976 require.Equal(t, result.Proofs[0]["domain"], sampleDomain) 1977 require.NotEmpty(t, result.Proofs[0]["jws"]) 1978 require.Equal(t, result.Proofs[0]["proofPurpose"], "authentication") 1979 require.Equal(t, result.Proofs[0]["type"], JSONWebSignature2020) 1980 require.Equal(t, result.Proofs[0]["verificationMethod"], vm) 1981 }) 1982 1983 t.Run("Test prove using JWT - success", func(t *testing.T) { 1984 walletInstance, err := New(user, mockctx) 1985 require.NotEmpty(t, walletInstance) 1986 require.NoError(t, err) 1987 1988 // unlock wallet 1989 authToken, err := walletInstance.Open(WithUnlockByPassphrase(samplePassPhrase)) 1990 require.NoError(t, err) 1991 require.NotEmpty(t, authToken) 1992 1993 defer walletInstance.Close() 1994 1995 // save one VC in store 1996 cleanup := addCredentialsToWallet(t, walletInstance, authToken, vcs["jwtvc"]) 1997 defer cleanup() 1998 1999 // import keys manually for signing presentation 2000 session, err := sessionManager().getSession(authToken) 2001 require.NotEmpty(t, session) 2002 require.NoError(t, err) 2003 2004 kmgr := session.KeyManager 2005 require.NotEmpty(t, kmgr) 2006 2007 edPriv := ed25519.PrivateKey(base58.Decode(pkBase58)) 2008 // nolint: errcheck, gosec 2009 kmgr.ImportPrivateKey(edPriv, kms.ED25519, kms.WithKeyID(kid)) 2010 2011 // sign with just controller (one stored & one raw bytes) 2012 result, err := walletInstance.Prove(authToken, 2013 &ProofOptions{ 2014 Controller: didKey, 2015 ProofFormat: ExternalJWTProofFormat, 2016 }, 2017 WithStoredCredentialsToProve(vcs["jwtvc"].ID), 2018 ) 2019 require.NoError(t, err) 2020 require.NotEmpty(t, result) 2021 require.Len(t, result.Proofs, 0) 2022 require.Len(t, result.Credentials(), 1) 2023 require.Equal(t, result.Holder, didKey) 2024 require.NotEmpty(t, result.JWT) 2025 }) 2026 2027 t.Run("Test prove without credentials (DIDAuth) - success", func(t *testing.T) { 2028 walletInstance, err := New(user, mockctx) 2029 require.NotEmpty(t, walletInstance) 2030 require.NoError(t, err) 2031 2032 // unlock wallet 2033 authToken, err := walletInstance.Open(WithUnlockByPassphrase(samplePassPhrase)) 2034 require.NoError(t, err) 2035 require.NotEmpty(t, authToken) 2036 2037 defer walletInstance.Close() 2038 2039 // import keys manually for signing presentation 2040 session, err := sessionManager().getSession(authToken) 2041 require.NotEmpty(t, session) 2042 require.NoError(t, err) 2043 2044 kmgr := session.KeyManager 2045 require.NotEmpty(t, kmgr) 2046 2047 edPriv := ed25519.PrivateKey(base58.Decode(pkBase58)) 2048 // nolint: errcheck, gosec 2049 kmgr.ImportPrivateKey(edPriv, kms.ED25519, kms.WithKeyID(kid)) 2050 2051 // prepare opts 2052 proofRepr := verifiable.SignatureJWS 2053 vm := sampleVerificationMethod 2054 created, err := time.Parse("2006-01-02", sampleCreatedDate) 2055 require.NoError(t, err) 2056 2057 result, err := walletInstance.Prove(authToken, &ProofOptions{ 2058 Controller: didKey, 2059 VerificationMethod: vm, 2060 ProofType: JSONWebSignature2020, 2061 Challenge: sampleChallenge, 2062 Domain: sampleDomain, 2063 Created: &created, 2064 ProofRepresentation: &proofRepr, 2065 }) 2066 require.NoError(t, err) 2067 require.NotEmpty(t, result) 2068 require.Empty(t, result.Credentials()) 2069 2070 require.Len(t, result.Proofs, 1) 2071 require.Equal(t, result.Proofs[0]["challenge"], sampleChallenge) 2072 require.Equal(t, result.Proofs[0]["created"], "2020-12-25T00:00:00Z") 2073 require.Equal(t, result.Proofs[0]["domain"], sampleDomain) 2074 require.NotEmpty(t, result.Proofs[0]["jws"]) 2075 require.Equal(t, result.Proofs[0]["proofPurpose"], "authentication") 2076 require.Equal(t, result.Proofs[0]["type"], JSONWebSignature2020) 2077 require.Equal(t, result.Proofs[0]["verificationMethod"], vm) 2078 }) 2079 2080 t.Run("Test prove failure - invalid credentials/presentation", func(t *testing.T) { 2081 walletInstance, err := New(user, mockctx) 2082 require.NotEmpty(t, walletInstance) 2083 require.NoError(t, err) 2084 2085 // unlock wallet 2086 authToken, err := walletInstance.Open(WithUnlockByPassphrase(samplePassPhrase)) 2087 require.NoError(t, err) 2088 require.NotEmpty(t, authToken) 2089 2090 defer walletInstance.Close() 2091 2092 result, err := walletInstance.Prove(authToken, &ProofOptions{}, WithRawCredentialsToProve([]byte("123"))) 2093 require.Empty(t, result) 2094 require.Error(t, err) 2095 require.Contains(t, err.Error(), "failed to resolve credentials from request") 2096 2097 result, err = walletInstance.Prove(authToken, &ProofOptions{}, 2098 WithStoredCredentialsToProve("non-existing-credential")) 2099 require.Empty(t, result) 2100 require.Error(t, err) 2101 require.Contains(t, err.Error(), "data not found") 2102 2103 // save invalid VC in store 2104 require.NoError(t, walletInstance.Add(authToken, Credential, []byte(sampleInvalidDIDContent))) 2105 result, err = walletInstance.Prove(authToken, &ProofOptions{}, 2106 WithStoredCredentialsToProve("did:example:sampleInvalidDIDContent")) 2107 require.Empty(t, result) 2108 require.Error(t, err) 2109 require.Contains(t, err.Error(), "build new credential") 2110 2111 result, err = walletInstance.Prove(authToken, &ProofOptions{}, 2112 WithRawPresentationToProve([]byte(sampleInvalidDIDContent))) 2113 require.Contains(t, err.Error(), "verifiable presentation is not valid") 2114 require.Empty(t, result) 2115 }) 2116 2117 t.Run("Test prove failures - proof option validation", func(t *testing.T) { 2118 walletInstance, err := New(user, mockctx) 2119 require.NotEmpty(t, walletInstance) 2120 require.NoError(t, err) 2121 2122 // unlock wallet 2123 authToken, err := walletInstance.Open(WithUnlockByPassphrase(samplePassPhrase)) 2124 require.NoError(t, err) 2125 require.NotEmpty(t, authToken) 2126 2127 defer walletInstance.Close() 2128 2129 // save all VCs in store 2130 cleanup := addCredentialsToWallet(t, walletInstance, authToken, vcs["edvc"], vcs["bbsvc"]) 2131 defer cleanup() 2132 2133 // no controller 2134 result, err := walletInstance.Prove(authToken, &ProofOptions{}, 2135 WithStoredCredentialsToProve(vcs["edvc"].ID, vcs["bbsvc"].ID)) 2136 require.Empty(t, result) 2137 require.Error(t, err) 2138 require.Contains(t, err.Error(), "invalid proof option, 'controller' is required") 2139 2140 // DID not found 2141 result, err = walletInstance.Prove(authToken, &ProofOptions{Controller: "did:example:1234"}, 2142 WithStoredCredentialsToProve(vcs["edvc"].ID, vcs["bbsvc"].ID)) 2143 require.Empty(t, result) 2144 require.Error(t, err) 2145 require.Contains(t, err.Error(), "failed to prepare proof: did not found") 2146 2147 // no assertion method 2148 result, err = walletInstance.Prove(authToken, &ProofOptions{Controller: sampleInvalidDIDID}, 2149 WithStoredCredentialsToProve(vcs["edvc"].ID, vcs["bbsvc"].ID)) 2150 require.Empty(t, result) 2151 require.Error(t, err) 2152 require.Contains(t, err.Error(), "unable to find 'authentication' for given verification method") 2153 }) 2154 2155 t.Run("Test prove using JWT - fail to generate JWT claims from invalid presentation", func(t *testing.T) { 2156 walletInstance, err := New(user, mockctx) 2157 require.NotEmpty(t, walletInstance) 2158 require.NoError(t, err) 2159 2160 // unlock wallet 2161 authToken, err := walletInstance.Open(WithUnlockByPassphrase(samplePassPhrase)) 2162 require.NoError(t, err) 2163 require.NotEmpty(t, authToken) 2164 2165 defer walletInstance.Close() 2166 2167 // sign with invalid Presentation 2168 _, err = walletInstance.Prove(authToken, 2169 &ProofOptions{ 2170 Controller: didKey, 2171 ProofFormat: ExternalJWTProofFormat, 2172 }, 2173 WithPresentationToProve(&verifiable.Presentation{ 2174 Proofs: []verifiable.Proof{ 2175 { 2176 "invalid": new(chan<- int), // can't marshal a channel 2177 }, 2178 }, 2179 }), 2180 ) 2181 require.Error(t, err) 2182 require.Contains(t, err.Error(), "failed to generate JWT claims for VP") 2183 }) 2184 2185 t.Run("Test prove using JWT - fail to sign VP", func(t *testing.T) { 2186 walletInstance, err := New(user, mockctx) 2187 require.NotEmpty(t, walletInstance) 2188 require.NoError(t, err) 2189 2190 // unlock wallet 2191 _, err = walletInstance.Open(WithUnlockByPassphrase(samplePassPhrase)) 2192 require.NoError(t, err) 2193 require.NotEmpty(t, issuerToken) 2194 2195 defer walletInstance.Close() 2196 2197 _, err = walletInstance.Prove("invalid auth token", 2198 &ProofOptions{ 2199 Controller: didKey, 2200 ProofFormat: ExternalJWTProofFormat, 2201 }, 2202 ) 2203 require.Error(t, err) 2204 require.Contains(t, err.Error(), "failed to generate JWT VP") 2205 }) 2206 2207 t.Run("Test VC wallet prove failure - add LD proof errors", func(t *testing.T) { 2208 walletInstance, err := New(user, mockctx) 2209 require.NotEmpty(t, walletInstance) 2210 require.NoError(t, err) 2211 2212 // wallet locked 2213 result, err := walletInstance.Prove(sampleFakeTkn, &ProofOptions{Controller: didKey}, 2214 WithStoredCredentialsToProve(vcs["edvc"].ID, vcs["bbsvc"].ID)) 2215 require.Empty(t, result) 2216 require.Error(t, err) 2217 require.Contains(t, err.Error(), "wallet locked") 2218 2219 // get token 2220 authToken, err := walletInstance.Open(WithUnlockByPassphrase(samplePassPhrase)) 2221 require.NoError(t, err) 2222 require.NotEmpty(t, authToken) 2223 2224 defer walletInstance.Close() 2225 2226 cleanup := addCredentialsToWallet(t, walletInstance, authToken, vcs["edvc"], vcs["bbsvc"]) 2227 defer cleanup() 2228 2229 // key not found 2230 result, err = walletInstance.Prove(authToken, &ProofOptions{ 2231 Controller: "did:key:z6MkjRagNiMu91DduvCvgEsqLZDVzrJzFrwahc4tXLt9DoHd", 2232 }, 2233 WithStoredCredentialsToProve(vcs["edvc"].ID, vcs["bbsvc"].ID)) 2234 require.Empty(t, result) 2235 require.Contains(t, err.Error(), "cannot read data for keysetID") 2236 2237 // import keys manually 2238 session, err := sessionManager().getSession(authToken) 2239 require.NotEmpty(t, session) 2240 require.NoError(t, err) 2241 2242 kmgr := session.KeyManager 2243 require.NotEmpty(t, kmgr) 2244 2245 edPriv := ed25519.PrivateKey(base58.Decode(pkBase58)) 2246 // nolint: errcheck, gosec 2247 kmgr.ImportPrivateKey(edPriv, kms.ED25519, kms.WithKeyID(kid)) 2248 2249 // invalid signature type 2250 result, err = walletInstance.Prove(authToken, &ProofOptions{ 2251 Controller: didKey, 2252 ProofType: "invalid", 2253 }, WithStoredCredentialsToProve(vcs["edvc"].ID, vcs["bbsvc"].ID)) 2254 require.Empty(t, result) 2255 require.Contains(t, err.Error(), " unsupported signature type 'invalid'") 2256 2257 // wrong key type 2258 result, err = walletInstance.Prove(authToken, &ProofOptions{ 2259 Controller: didKey, 2260 ProofType: BbsBlsSignature2020, 2261 }, WithStoredCredentialsToProve(vcs["edvc"].ID, vcs["bbsvc"].ID)) 2262 require.Empty(t, result) 2263 require.Contains(t, err.Error(), "failed to add linked data proof") 2264 }) 2265 } 2266 2267 func Test_AddContext(t *testing.T) { 2268 loader, err := ldtestutil.DocumentLoader() 2269 require.NoError(t, err) 2270 2271 vc, err := verifiable.ParseCredential(testdata.SampleUDCVC, verifiable.WithJSONLDDocumentLoader(loader)) 2272 require.NoError(t, err) 2273 require.NotEmpty(t, vc) 2274 2275 require.Len(t, vc.Context, 3) 2276 addContext(vc, bbsContext) 2277 require.Len(t, vc.Context, 3) 2278 addContext(vc, bbsContext+".01") 2279 require.Len(t, vc.Context, 4) 2280 } 2281 2282 func TestWallet_Verify(t *testing.T) { 2283 user := uuid.New().String() 2284 customVDR := &mockvdr.MockVDRegistry{ 2285 ResolveFunc: func(didID string, opts ...vdrapi.DIDMethodOption) (*did.DocResolution, error) { 2286 if didID == sampleInvalidDIDID { 2287 d, e := did.ParseDocument(testdata.SampleInvalidDID) 2288 require.NoError(t, e) 2289 2290 return &did.DocResolution{DIDDocument: d}, nil 2291 } else if strings.HasPrefix(didID, "did:key:") { 2292 k := key.New() 2293 2294 d, e := k.Read(didID) 2295 if e != nil { 2296 return nil, e 2297 } 2298 2299 return d, nil 2300 } 2301 2302 return nil, fmt.Errorf("did not found") 2303 }, 2304 } 2305 2306 sampleCrypto, err := tinkcrypto.New() 2307 require.NoError(t, err) 2308 2309 mockctx := newMockProvider(t) 2310 mockctx.VDRegistryValue = customVDR 2311 mockctx.CryptoValue = sampleCrypto 2312 2313 err = CreateProfile(user, mockctx, WithPassphrase(samplePassPhrase)) 2314 require.NoError(t, err) 2315 2316 walletForIssue, err := New(user, mockctx) 2317 require.NoError(t, err) 2318 2319 tkn, err := walletForIssue.Open(WithUnlockByPassphrase(samplePassPhrase)) 2320 require.NoError(t, err) 2321 require.NotEmpty(t, tkn) 2322 2323 // import keys manually 2324 session, err := sessionManager().getSession(tkn) 2325 require.NotEmpty(t, session) 2326 require.NoError(t, err) 2327 2328 kmgr := session.KeyManager 2329 require.NotEmpty(t, kmgr) 2330 2331 edPriv := ed25519.PrivateKey(base58.Decode(pkBase58)) 2332 // nolint: errcheck, gosec 2333 kmgr.ImportPrivateKey(edPriv, kms.ED25519, kms.WithKeyID(kid)) 2334 2335 // issue a credential 2336 sampleVC, err := walletForIssue.Issue(tkn, testdata.SampleUDCVC, &ProofOptions{ 2337 Controller: didKey, 2338 }) 2339 require.NoError(t, err) 2340 require.NotEmpty(t, sampleVC) 2341 require.Len(t, sampleVC.Proofs, 1) 2342 2343 templateCred, err := verifiable.ParseCredential(testdata.SampleUDCVC, verifiable.WithDisabledProofCheck(), 2344 verifiable.WithJSONLDDocumentLoader(walletForIssue.jsonldDocumentLoader)) 2345 require.NoError(t, err) 2346 2347 templateCred.Issuer.ID = didKey 2348 2349 templateData, err := templateCred.MarshalJSON() 2350 require.NoError(t, err) 2351 2352 // issue a JWT credential 2353 sampleJWTVC, err := walletForIssue.Issue(tkn, templateData, &ProofOptions{ 2354 Controller: didKey, 2355 VerificationMethod: sampleVerificationMethod, 2356 ProofFormat: ExternalJWTProofFormat, 2357 }) 2358 require.NoError(t, err) 2359 require.NotEmpty(t, sampleJWTVC) 2360 require.NotEqual(t, "", sampleJWTVC.JWT) 2361 require.True(t, jwt.IsJWS(sampleJWTVC.JWT)) 2362 2363 // present a credential 2364 sampleVP, err := walletForIssue.Prove(tkn, &ProofOptions{Controller: didKey}, 2365 WithCredentialsToProve(sampleVC)) 2366 require.NoError(t, err) 2367 require.NotEmpty(t, sampleVP) 2368 require.Len(t, sampleVP.Proofs, 1) 2369 2370 // present a tampered credential 2371 invalidVC := *sampleVC 2372 invalidVC.Issuer.ID += "." 2373 sampleInvalidVP, err := walletForIssue.Prove(tkn, &ProofOptions{Controller: didKey}, 2374 WithCredentialsToProve(&invalidVC)) 2375 require.NoError(t, err) 2376 require.NotEmpty(t, sampleInvalidVP) 2377 require.Len(t, sampleInvalidVP.Proofs, 1) 2378 2379 require.True(t, walletForIssue.Close()) 2380 2381 t.Run("Test VC wallet verifying a credential - success", func(t *testing.T) { 2382 walletInstance, err := New(user, mockctx) 2383 require.NotEmpty(t, walletInstance) 2384 require.NoError(t, err) 2385 2386 tkn, err := walletInstance.Open(WithUnlockByPassphrase(samplePassPhrase)) 2387 require.NoError(t, err) 2388 require.NotEmpty(t, tkn) 2389 2390 // save it in store 2391 vcBytes, err := sampleVC.MarshalJSON() 2392 require.NoError(t, err) 2393 require.NoError(t, walletInstance.Add(tkn, Credential, vcBytes)) 2394 2395 // verify stored credential 2396 ok, err := walletInstance.Verify(tkn, WithStoredCredentialToVerify(sampleVC.ID)) 2397 require.NoError(t, err) 2398 require.True(t, ok) 2399 2400 // verify raw credential 2401 rawBytes, err := sampleVC.MarshalJSON() 2402 require.NoError(t, err) 2403 ok, err = walletInstance.Verify(tkn, WithRawCredentialToVerify(rawBytes)) 2404 require.NoError(t, err) 2405 require.True(t, ok) 2406 2407 require.NoError(t, walletInstance.Remove(tkn, Credential, "http://example.edu/credentials/1872")) 2408 2409 // verify JWT Credential object 2410 jwtBytes, err := sampleJWTVC.MarshalJSON() 2411 require.NoError(t, err) 2412 ok, err = walletInstance.Verify(tkn, WithRawCredentialToVerify(jwtBytes)) 2413 require.NoError(t, err) 2414 require.True(t, ok) 2415 2416 // verify raw JWT credential 2417 ok, err = walletInstance.Verify(tkn, WithRawCredentialToVerify([]byte(sampleJWTVC.JWT))) 2418 require.NoError(t, err) 2419 require.True(t, ok) 2420 2421 require.True(t, walletInstance.Close()) 2422 }) 2423 2424 t.Run("Test VC wallet verifying a presentation - success", func(t *testing.T) { 2425 walletInstance, err := New(user, mockctx) 2426 require.NotEmpty(t, walletInstance) 2427 require.NoError(t, err) 2428 2429 tkn, err := walletInstance.Open(WithUnlockByPassphrase(samplePassPhrase)) 2430 require.NoError(t, err) 2431 require.NotEmpty(t, tkn) 2432 2433 // verify a raw presentation 2434 rawBytes, err := sampleVP.MarshalJSON() 2435 require.NoError(t, err) 2436 ok, err := walletInstance.Verify(tkn, WithRawPresentationToVerify(rawBytes)) 2437 require.NoError(t, err) 2438 require.True(t, ok) 2439 2440 require.True(t, walletInstance.Close()) 2441 }) 2442 2443 t.Run("Test VC wallet verifying a credential - invalid signature", func(t *testing.T) { 2444 walletInstance, err := New(user, mockctx) 2445 require.NotEmpty(t, walletInstance) 2446 require.NoError(t, err) 2447 2448 tkn, err := walletInstance.Open(WithUnlockByPassphrase(samplePassPhrase)) 2449 require.NoError(t, err) 2450 require.NotEmpty(t, tkn) 2451 2452 // save tampered VC in store 2453 // save it in store 2454 tamperedVC := *sampleVC 2455 tamperedVC.Issuer.ID += "." 2456 vcBytes, err := tamperedVC.MarshalJSON() 2457 require.NoError(t, err) 2458 require.NoError(t, walletInstance.Add(tkn, Credential, vcBytes)) 2459 2460 ok, err := walletInstance.Verify(tkn, WithStoredCredentialToVerify("http://example.edu/credentials/1872")) 2461 require.Error(t, err) 2462 require.Contains(t, err.Error(), "invalid signature") 2463 require.False(t, ok) 2464 2465 // verify raw credential 2466 rawBytes, err := tamperedVC.MarshalJSON() 2467 require.NoError(t, err) 2468 ok, err = walletInstance.Verify(tkn, WithRawCredentialToVerify(rawBytes)) 2469 require.Contains(t, err.Error(), "invalid signature") 2470 require.False(t, ok) 2471 2472 require.True(t, walletInstance.Close()) 2473 }) 2474 2475 t.Run("Test VC wallet verifying a presentation - invalid signature", func(t *testing.T) { 2476 walletInstance, err := New(user, mockctx) 2477 require.NotEmpty(t, walletInstance) 2478 require.NoError(t, err) 2479 2480 tkn, err := walletInstance.Open(WithUnlockByPassphrase(samplePassPhrase)) 2481 require.NoError(t, err) 2482 require.NotEmpty(t, tkn) 2483 2484 // verify a raw presentation 2485 tamperedVP := *sampleVP 2486 tamperedVP.Holder += "." 2487 rawBytes, err := tamperedVP.MarshalJSON() 2488 require.NoError(t, err) 2489 ok, err := walletInstance.Verify(tkn, WithRawPresentationToVerify(rawBytes)) 2490 require.Contains(t, err.Error(), "invalid signature") 2491 require.False(t, ok) 2492 2493 require.True(t, walletInstance.Close()) 2494 }) 2495 2496 t.Run("Test VC wallet verifying a presentation - invalid credential signature", func(t *testing.T) { 2497 walletInstance, err := New(user, mockctx) 2498 require.NotEmpty(t, walletInstance) 2499 require.NoError(t, err) 2500 2501 tkn, err := walletInstance.Open(WithUnlockByPassphrase(samplePassPhrase)) 2502 require.NoError(t, err) 2503 require.NotEmpty(t, tkn) 2504 2505 // verify a raw presentation 2506 rawBytes, err := sampleInvalidVP.MarshalJSON() 2507 require.NoError(t, err) 2508 ok, err := walletInstance.Verify(tkn, WithRawPresentationToVerify(rawBytes)) 2509 require.Contains(t, err.Error(), "presentation verification failed: credential verification failed:") 2510 require.Contains(t, err.Error(), "invalid signature") 2511 require.False(t, ok) 2512 2513 require.True(t, walletInstance.Close()) 2514 }) 2515 2516 t.Run("Test VC wallet verifying a credential - invalid credential ID", func(t *testing.T) { 2517 walletInstance, err := New(user, mockctx) 2518 require.NotEmpty(t, walletInstance) 2519 require.NoError(t, err) 2520 2521 tkn, err := walletInstance.Open(WithUnlockByPassphrase(samplePassPhrase)) 2522 require.NoError(t, err) 2523 require.NotEmpty(t, tkn) 2524 2525 // verify non existent credential. 2526 ok, err := walletInstance.Verify(tkn, WithStoredCredentialToVerify("invalid-ID")) 2527 require.Error(t, err) 2528 require.Contains(t, err.Error(), "failed to get credential") 2529 require.False(t, ok) 2530 2531 require.True(t, walletInstance.Close()) 2532 }) 2533 2534 t.Run("Test VC wallet verifying a credential - invalid request", func(t *testing.T) { 2535 walletInstance, err := New(user, mockctx) 2536 require.NotEmpty(t, walletInstance) 2537 require.NoError(t, err) 2538 2539 tkn, err := walletInstance.Open(WithUnlockByPassphrase(samplePassPhrase)) 2540 require.NoError(t, err) 2541 require.NotEmpty(t, tkn) 2542 2543 // verify non existent credential. 2544 ok, err := walletInstance.Verify(tkn, WithStoredCredentialToVerify("")) 2545 require.Error(t, err) 2546 require.Contains(t, err.Error(), "invalid verify request") 2547 require.False(t, ok) 2548 2549 require.True(t, walletInstance.Close()) 2550 }) 2551 } 2552 2553 func TestWallet_Derive(t *testing.T) { 2554 user := uuid.New().String() 2555 customVDR := &mockvdr.MockVDRegistry{ 2556 ResolveFunc: func(didID string, opts ...vdrapi.DIDMethodOption) (*did.DocResolution, error) { 2557 if didID == sampleInvalidDIDID { 2558 d, e := did.ParseDocument(testdata.SampleInvalidDID) 2559 require.NoError(t, e) 2560 2561 return &did.DocResolution{DIDDocument: d}, nil 2562 } else if strings.HasPrefix(didID, "did:key:") { 2563 k := key.New() 2564 2565 d, e := k.Read(didID) 2566 if e != nil { 2567 return nil, e 2568 } 2569 2570 return d, nil 2571 } 2572 2573 return nil, fmt.Errorf("did not found") 2574 }, 2575 } 2576 2577 mockctx := newMockProvider(t) 2578 mockctx.VDRegistryValue = customVDR 2579 2580 customCrypto, err := tinkcrypto.New() 2581 require.NoError(t, err) 2582 2583 mockctx.CryptoValue = customCrypto 2584 2585 // create profile 2586 err = CreateProfile(user, mockctx, WithPassphrase(samplePassPhrase)) 2587 require.NoError(t, err) 2588 2589 // prepare VCs for tests 2590 vcs := make(map[string]*verifiable.Credential, 2) 2591 walletForIssue, err := New(user, mockctx) 2592 require.NotEmpty(t, walletForIssue) 2593 require.NoError(t, err) 2594 2595 authToken, err := walletForIssue.Open(WithUnlockByPassphrase(samplePassPhrase)) 2596 require.NoError(t, err) 2597 require.NotEmpty(t, authToken) 2598 2599 // import ED25519 & BLS12381G2Type keys manually 2600 session, err := sessionManager().getSession(authToken) 2601 require.NotEmpty(t, session) 2602 require.NoError(t, err) 2603 2604 kmgr := session.KeyManager 2605 require.NotEmpty(t, kmgr) 2606 2607 edPriv := ed25519.PrivateKey(base58.Decode(pkBase58)) 2608 // nolint: errcheck, gosec 2609 kmgr.ImportPrivateKey(edPriv, kms.ED25519, kms.WithKeyID(kid)) 2610 2611 privKeyBBS, err := bbs12381g2pub.UnmarshalPrivateKey(base58.Decode(pkBBSBase58)) 2612 require.NoError(t, err) 2613 // nolint: errcheck, gosec 2614 kmgr.ImportPrivateKey(privKeyBBS, kms.BLS12381G2Type, kms.WithKeyID(keyIDBBS)) 2615 2616 // issue a credential with Ed25519Signature2018 2617 result, err := walletForIssue.Issue(authToken, testdata.SampleUDCVC, &ProofOptions{ 2618 Controller: didKey, 2619 }) 2620 require.NoError(t, err) 2621 require.NotEmpty(t, result) 2622 require.Len(t, result.Proofs, 1) 2623 vcs["edvc"] = result 2624 2625 // issue a credential with BbsBlsSignature2020 2626 proofRepr := verifiable.SignatureProofValue 2627 result, err = walletForIssue.Issue(authToken, testdata.SampleUDCVC, &ProofOptions{ 2628 Controller: didKeyBBS, 2629 ProofType: BbsBlsSignature2020, 2630 ProofRepresentation: &proofRepr, 2631 }) 2632 require.NoError(t, err) 2633 require.NotEmpty(t, result) 2634 require.Len(t, result.Proofs, 1) 2635 vcs["bbsvc"] = result 2636 2637 require.True(t, walletForIssue.Close()) 2638 2639 // prepare frame 2640 var frameDoc map[string]interface{} 2641 2642 require.NoError(t, json.Unmarshal(testdata.SampleFrame, &frameDoc)) 2643 2644 t.Run("Test derive a credential from wallet - success", func(t *testing.T) { 2645 walletInstance, err := New(user, mockctx) 2646 require.NotEmpty(t, walletInstance) 2647 require.NoError(t, err) 2648 2649 tkn, err := walletInstance.Open(WithUnlockByPassphrase(samplePassPhrase)) 2650 require.NoError(t, err) 2651 2652 // save BBS VC in store 2653 vcBytes, err := vcs["bbsvc"].MarshalJSON() 2654 require.NoError(t, err) 2655 require.NoError(t, walletInstance.Add(tkn, Credential, vcBytes)) 2656 2657 sampleNonce := uuid.New().String() 2658 2659 verifyBBSProof := func(proofs []verifiable.Proof) { 2660 require.Len(t, proofs, 1) 2661 require.NotEmpty(t, proofs[0]) 2662 require.Equal(t, proofs[0]["type"], "BbsBlsSignatureProof2020") 2663 require.NotEmpty(t, proofs[0]["nonce"]) 2664 require.EqualValues(t, proofs[0]["nonce"], base64.StdEncoding.EncodeToString([]byte(sampleNonce))) 2665 require.NotEmpty(t, proofs[0]["proofValue"]) 2666 } 2667 2668 // derive stored credential 2669 vc, err := walletInstance.Derive(tkn, FromStoredCredential(vcs["bbsvc"].ID), &DeriveOptions{ 2670 Nonce: sampleNonce, 2671 Frame: frameDoc, 2672 }) 2673 require.NoError(t, err) 2674 require.NotEmpty(t, vc) 2675 verifyBBSProof(vc.Proofs) 2676 2677 // derive raw credential 2678 vc, err = walletInstance.Derive(tkn, FromRawCredential(vcBytes), &DeriveOptions{ 2679 Nonce: sampleNonce, 2680 Frame: frameDoc, 2681 }) 2682 require.NoError(t, err) 2683 require.NotEmpty(t, vc) 2684 verifyBBSProof(vc.Proofs) 2685 2686 // derive from credential instance 2687 vc, err = walletInstance.Derive(tkn, FromCredential(vcs["bbsvc"]), &DeriveOptions{ 2688 Nonce: sampleNonce, 2689 Frame: frameDoc, 2690 }) 2691 require.NoError(t, err) 2692 require.NotEmpty(t, vc) 2693 verifyBBSProof(vc.Proofs) 2694 2695 require.True(t, walletInstance.Close()) 2696 }) 2697 2698 t.Run("Test derive credential failures", func(t *testing.T) { 2699 walletInstance, err := New(user, mockctx) 2700 require.NotEmpty(t, walletInstance) 2701 require.NoError(t, err) 2702 2703 tkn, err := walletInstance.Open(WithUnlockByPassphrase(samplePassPhrase)) 2704 require.NoError(t, err) 2705 2706 // invalid request 2707 vc, err := walletInstance.Derive(tkn, FromStoredCredential(""), &DeriveOptions{}) 2708 require.Empty(t, vc) 2709 require.Error(t, err) 2710 require.Contains(t, err.Error(), "invalid request to derive credential") 2711 2712 // credential not found in store 2713 vc, err = walletInstance.Derive(tkn, FromStoredCredential("invalid-id"), &DeriveOptions{}) 2714 require.Empty(t, vc) 2715 require.Error(t, err) 2716 require.Contains(t, err.Error(), "data not found") 2717 2718 // invalid credential in store 2719 require.NoError(t, walletInstance.Add(tkn, Credential, []byte(sampleInvalidDIDContent))) 2720 2721 vc, err = walletInstance.Derive(tkn, FromStoredCredential("did:example:sampleInvalidDIDContent"), &DeriveOptions{}) 2722 require.Empty(t, vc) 2723 require.Error(t, err) 2724 require.Contains(t, err.Error(), "credential type of unknown structure") 2725 2726 // invalid raw credential 2727 vc, err = walletInstance.Derive(tkn, FromRawCredential([]byte(sampleInvalidDIDContent)), &DeriveOptions{}) 2728 require.Empty(t, vc) 2729 require.Error(t, err) 2730 require.Contains(t, err.Error(), "credential type of unknown structure") 2731 2732 // invalid raw credential 2733 vc, err = walletInstance.Derive(tkn, FromCredential(vcs["bbsvc"]), &DeriveOptions{}) 2734 require.Empty(t, vc) 2735 require.Error(t, err) 2736 require.Contains(t, err.Error(), "failed to derive credential") 2737 2738 // try deriving wrong proof type - no BbsBlsSignature2020 proof present 2739 vc, err = walletInstance.Derive(tkn, FromCredential(vcs["edvc"]), &DeriveOptions{ 2740 Frame: frameDoc, 2741 }) 2742 require.Empty(t, vc) 2743 require.Error(t, err) 2744 require.Contains(t, err.Error(), "no BbsBlsSignature2020 proof present") 2745 2746 require.True(t, walletInstance.Close()) 2747 }) 2748 } 2749 2750 func TestWallet_CreateKeyPair(t *testing.T) { 2751 sampleKeyPairUser := uuid.New().String() 2752 mockctx := newMockProvider(t) 2753 err := CreateProfile(sampleKeyPairUser, mockctx, WithPassphrase(samplePassPhrase)) 2754 require.NoError(t, err) 2755 2756 wallet, err := New(sampleKeyPairUser, mockctx) 2757 require.NoError(t, err) 2758 require.NotEmpty(t, wallet) 2759 2760 token, err := wallet.Open(WithUnlockByPassphrase(samplePassPhrase), WithUnlockExpiry(500*time.Millisecond)) 2761 require.NoError(t, err) 2762 require.NotEmpty(t, token) 2763 2764 defer wallet.Close() 2765 2766 t.Run("test creating key pair", func(t *testing.T) { 2767 keyPair, err := wallet.CreateKeyPair(token, kms.ED25519) 2768 require.NoError(t, err) 2769 require.NotEmpty(t, keyPair) 2770 require.NotEmpty(t, keyPair.KeyID) 2771 require.NotEmpty(t, keyPair.PublicKey) 2772 }) 2773 2774 t.Run("test creating key pair with invalid auth", func(t *testing.T) { 2775 keyPair, err := wallet.CreateKeyPair(sampleFakeTkn, kms.ED25519) 2776 require.True(t, errors.Is(err, ErrInvalidAuthToken)) 2777 require.Empty(t, keyPair) 2778 }) 2779 2780 t.Run("test failure while creating key pair", func(t *testing.T) { 2781 keyPair, err := wallet.CreateKeyPair(token, kms.KeyType("invalid")) 2782 require.Error(t, err) 2783 require.Contains(t, err.Error(), "failed to create new key") 2784 require.Empty(t, keyPair) 2785 }) 2786 } 2787 2788 func TestWallet_ResolveCredentialManifest(t *testing.T) { 2789 mockctx := newMockProvider(t) 2790 user := uuid.New().String() 2791 2792 // create a wallet 2793 err := CreateProfile(user, mockctx, WithPassphrase(samplePassPhrase)) 2794 require.NoError(t, err) 2795 2796 wallet, err := New(user, mockctx) 2797 require.NoError(t, err) 2798 require.NotEmpty(t, wallet) 2799 2800 // get token 2801 token, err := wallet.Open(WithUnlockByPassphrase(samplePassPhrase), WithUnlockExpiry(500*time.Millisecond)) 2802 require.NoError(t, err) 2803 require.NotEmpty(t, token) 2804 2805 responseVP, err := verifiable.ParsePresentation(testdata.CredentialResponseWithMultipleVCs, 2806 verifiable.WithPresDisabledProofCheck(), 2807 verifiable.WithPresJSONLDDocumentLoader(mockctx.JSONLDDocumentLoader())) 2808 require.NoError(t, err) 2809 2810 vc, err := verifiable.ParseCredential(testdata.SampleUDCVC, 2811 verifiable.WithJSONLDDocumentLoader(mockctx.JSONLDDocumentLoader())) 2812 require.NoError(t, err) 2813 2814 require.NoError(t, wallet.Add(token, Credential, testdata.SampleUDCVC)) 2815 2816 t.Run("Test Resolving credential manifests", func(t *testing.T) { 2817 testTable := map[string]struct { 2818 manifest []byte 2819 resolve ResolveManifestOption 2820 resultCount int 2821 error string 2822 }{ 2823 "testing resolve by raw credential response": { 2824 manifest: testdata.CredentialManifestMultipleVCs, 2825 resolve: ResolveRawResponse(testdata.CredentialResponseWithMultipleVCs), 2826 resultCount: 2, 2827 }, 2828 "testing resolve by credential response": { 2829 manifest: testdata.CredentialManifestMultipleVCs, 2830 resolve: ResolveResponse(responseVP), 2831 resultCount: 2, 2832 }, 2833 "testing resolve by raw credential": { 2834 manifest: testdata.CredentialManifestMultipleVCs, 2835 resolve: ResolveRawCredential("udc_output", testdata.SampleUDCVC), 2836 resultCount: 1, 2837 }, 2838 "testing resolve by raw JWT credential": { 2839 manifest: testdata.CredentialManifestMultipleVCs, 2840 resolve: ResolveRawCredential("udc_output", testdata.SampleUDCJWTVC), 2841 resultCount: 1, 2842 }, 2843 "testing resolve by credential": { 2844 manifest: testdata.CredentialManifestMultipleVCs, 2845 resolve: ResolveCredential("udc_output", vc), 2846 resultCount: 1, 2847 }, 2848 "testing resolve by credential ID": { 2849 manifest: testdata.CredentialManifestMultipleVCs, 2850 resolve: ResolveCredentialID("udc_output", vc.ID), 2851 resultCount: 1, 2852 }, 2853 "testing failure - resolve by empty resolve option": { 2854 manifest: testdata.CredentialManifestMultipleVCs, 2855 resolve: ResolveCredential("udc_output", nil), 2856 resultCount: 0, 2857 error: "invalid option", 2858 }, 2859 "testing failure - resolve by invalid raw response": { 2860 manifest: testdata.CredentialManifestMultipleVCs, 2861 resolve: ResolveRawResponse([]byte("{}")), 2862 resultCount: 0, 2863 error: "verifiable presentation is not valid", 2864 }, 2865 "testing failure - resolve by invalid raw credential": { 2866 manifest: testdata.CredentialManifestMultipleVCs, 2867 resolve: ResolveRawCredential("", []byte("{}")), 2868 resultCount: 0, 2869 error: "credential type of unknown structure", 2870 }, 2871 "testing failure - invalid credential manifest": { 2872 manifest: []byte("{}"), 2873 resolve: ResolveResponse(responseVP), 2874 resultCount: 0, 2875 error: "invalid credential manifest", 2876 }, 2877 "testing failure - resolve raw credential by invalid descriptor ID": { 2878 manifest: testdata.CredentialManifestMultipleVCs, 2879 resolve: ResolveRawCredential("invalid", testdata.SampleUDCVC), 2880 resultCount: 0, 2881 error: "unable to find matching descriptor", 2882 }, 2883 "testing failure - resolve credential by invalid descriptor ID": { 2884 manifest: testdata.CredentialManifestMultipleVCs, 2885 resolve: ResolveCredential("invalid", vc), 2886 resultCount: 0, 2887 error: "unable to find matching descriptor", 2888 }, 2889 "testing failure - resolve credential by invalid credential ID": { 2890 manifest: testdata.CredentialManifestMultipleVCs, 2891 resolve: ResolveCredentialID("udc_output", "incorrect"), 2892 resultCount: 0, 2893 error: "failed to get credential to resolve from wallet", 2894 }, 2895 } 2896 2897 t.Parallel() 2898 2899 for testName, testData := range testTable { 2900 t.Run(testName, func(t *testing.T) { 2901 resolved, err := wallet.ResolveCredentialManifest(token, testData.manifest, testData.resolve) 2902 2903 if testData.error != "" { 2904 require.Error(t, err) 2905 require.Contains(t, err.Error(), testData.error) 2906 require.Len(t, resolved, testData.resultCount) 2907 2908 return 2909 } 2910 2911 require.NoError(t, err) 2912 require.NotEmpty(t, resolved) 2913 require.Len(t, resolved, testData.resultCount) 2914 2915 for _, result := range resolved { 2916 require.NotEmpty(t, result.DescriptorID) 2917 require.NotEmpty(t, result.Title) 2918 require.NotEmpty(t, result.Properties) 2919 } 2920 }) 2921 } 2922 }) 2923 } 2924 2925 func TestWallet_verifiableClaimsToJWT(t *testing.T) { 2926 customVDR := &mockvdr.MockVDRegistry{ 2927 ResolveFunc: func(didID string, opts ...vdrapi.DIDMethodOption) (*did.DocResolution, error) { 2928 if didID == sampleInvalidDIDID { 2929 d, e := did.ParseDocument(testdata.SampleInvalidDID) 2930 require.NoError(t, e) 2931 2932 return &did.DocResolution{DIDDocument: d}, nil 2933 } else if strings.HasPrefix(didID, "did:key:") { 2934 k := key.New() 2935 2936 d, e := k.Read(didID) 2937 if e != nil { 2938 return nil, e 2939 } 2940 2941 return d, nil 2942 } 2943 2944 return nil, fmt.Errorf("did not found") 2945 }, 2946 } 2947 2948 user := uuid.New().String() 2949 2950 mockctx := newMockProvider(t) 2951 mockctx.VDRegistryValue = customVDR 2952 mockctx.CryptoValue = &cryptomock.Crypto{} 2953 2954 err := CreateProfile(user, mockctx, WithPassphrase(samplePassPhrase)) 2955 require.NoError(t, err) 2956 2957 t.Run("success", func(t *testing.T) { 2958 type keyImporterFunc func(kmgr kms.KeyManager) (string, string, error) 2959 2960 ecKeyTestCase := func( 2961 curve elliptic.Curve, 2962 fpCodec uint64, 2963 kt kms.KeyType, 2964 ) keyImporterFunc { 2965 return func(kmgr kms.KeyManager) (string, string, error) { 2966 priv, err := ecdsa.GenerateKey(curve, rand.Reader) 2967 if err != nil { 2968 return "", "", err 2969 } 2970 2971 pubKeyBytes := elliptic.MarshalCompressed(priv.Curve, priv.X, priv.Y) 2972 2973 fp := fingerprint.KeyFingerprint(fpCodec, pubKeyBytes) 2974 k, vm := fingerprint.CreateDIDKeyByCode(fpCodec, pubKeyBytes) 2975 2976 // nolint: errcheck, gosec 2977 kmgr.ImportPrivateKey(priv, kt, kms.WithKeyID(fp)) 2978 2979 return k, vm, nil 2980 } 2981 } 2982 2983 testCases := []struct { 2984 name string 2985 keyFunc keyImporterFunc 2986 }{ 2987 { 2988 name: "Ed25519", 2989 keyFunc: func(kmgr kms.KeyManager) (string, string, error) { 2990 edPriv := ed25519.PrivateKey(base58.Decode(pkBase58)) 2991 // nolint: errcheck, gosec 2992 kmgr.ImportPrivateKey(edPriv, kms.ED25519, kms.WithKeyID(kid)) 2993 2994 return didKey, sampleVerificationMethod, nil 2995 }, 2996 }, 2997 { 2998 name: "P256", 2999 keyFunc: ecKeyTestCase(elliptic.P256(), fingerprint.P256PubKeyMultiCodec, kms.ECDSAP256TypeIEEEP1363), 3000 }, 3001 { 3002 name: "P384", 3003 keyFunc: ecKeyTestCase(elliptic.P384(), fingerprint.P384PubKeyMultiCodec, kms.ECDSAP384TypeIEEEP1363), 3004 }, 3005 { 3006 name: "P521", 3007 keyFunc: ecKeyTestCase(elliptic.P521(), fingerprint.P521PubKeyMultiCodec, kms.ECDSAP521TypeIEEEP1363), 3008 }, 3009 } 3010 3011 for _, tc := range testCases { 3012 t.Run(tc.name, func(t *testing.T) { 3013 walletInstance, err := New(user, mockctx) 3014 require.NotEmpty(t, walletInstance) 3015 require.NoError(t, err) 3016 3017 // unlock wallet 3018 authToken, err := walletInstance.Open(WithUnlockByPassphrase(samplePassPhrase)) 3019 require.NoError(t, err) 3020 require.NotEmpty(t, authToken) 3021 3022 defer walletInstance.Close() 3023 3024 // add private key 3025 session, err := sessionManager().getSession(authToken) 3026 require.NotEmpty(t, session) 3027 require.NoError(t, err) 3028 3029 kmgr := session.KeyManager 3030 require.NotEmpty(t, kmgr) 3031 3032 k, vm, err := tc.keyFunc(kmgr) 3033 require.NoError(t, err) 3034 3035 _, err = walletInstance.verifiableClaimsToJWT(authToken, &verifiable.JWTCredClaims{}, &ProofOptions{ 3036 Controller: k, 3037 VerificationMethod: vm, 3038 }) 3039 require.NoError(t, err) 3040 }) 3041 } 3042 }) 3043 3044 t.Run("error initializing KMS signer", func(t *testing.T) { 3045 walletInstance, err := New(user, mockctx) 3046 require.NotEmpty(t, walletInstance) 3047 require.NoError(t, err) 3048 3049 // unlock wallet 3050 authToken, err := walletInstance.Open(WithUnlockByPassphrase(samplePassPhrase)) 3051 require.NoError(t, err) 3052 require.NotEmpty(t, authToken) 3053 3054 defer walletInstance.Close() 3055 3056 _, err = walletInstance.verifiableClaimsToJWT(authToken, nil, &ProofOptions{}) 3057 require.Error(t, err) 3058 require.Contains(t, err.Error(), "initializing signer") 3059 }) 3060 3061 t.Run("unsupported keytype", func(t *testing.T) { 3062 walletInstance, err := New(user, mockctx) 3063 require.NotEmpty(t, walletInstance) 3064 require.NoError(t, err) 3065 3066 // unlock wallet 3067 authToken, err := walletInstance.Open(WithUnlockByPassphrase(samplePassPhrase)) 3068 require.NoError(t, err) 3069 require.NotEmpty(t, authToken) 3070 3071 defer walletInstance.Close() 3072 3073 // add private key 3074 session, err := sessionManager().getSession(authToken) 3075 require.NotEmpty(t, session) 3076 require.NoError(t, err) 3077 3078 kmgr := session.KeyManager 3079 require.NotEmpty(t, kmgr) 3080 3081 privKeyBBS, err := bbs12381g2pub.UnmarshalPrivateKey(base58.Decode(pkBBSBase58)) 3082 require.NoError(t, err) 3083 // nolint: errcheck, gosec 3084 kmgr.ImportPrivateKey(privKeyBBS, kms.BLS12381G2Type, kms.WithKeyID(keyIDBBS)) 3085 3086 _, err = walletInstance.verifiableClaimsToJWT(authToken, &verifiable.JWTCredClaims{}, &ProofOptions{ 3087 Controller: didKeyBBS, 3088 VerificationMethod: didKeyBBS + "#" + keyIDBBS, 3089 }) 3090 require.Error(t, err) 3091 require.Contains(t, err.Error(), "unsupported keytype for JWT") 3092 }) 3093 3094 t.Run("fail to sign", func(t *testing.T) { 3095 walletInstance, err := New(user, mockctx) 3096 require.NotEmpty(t, walletInstance) 3097 require.NoError(t, err) 3098 3099 expectErr := errors.New("expected error") 3100 3101 walletInstance.walletCrypto = &cryptomock.Crypto{ 3102 SignErr: expectErr, 3103 } 3104 3105 // unlock wallet 3106 authToken, err := walletInstance.Open(WithUnlockByPassphrase(samplePassPhrase)) 3107 require.NoError(t, err) 3108 require.NotEmpty(t, authToken) 3109 3110 defer walletInstance.Close() 3111 3112 // add private key 3113 session, err := sessionManager().getSession(authToken) 3114 require.NotEmpty(t, session) 3115 require.NoError(t, err) 3116 3117 kmgr := session.KeyManager 3118 require.NotEmpty(t, kmgr) 3119 3120 edPriv := ed25519.PrivateKey(base58.Decode(pkBase58)) 3121 // nolint: errcheck, gosec 3122 kmgr.ImportPrivateKey(edPriv, kms.ED25519, kms.WithKeyID(kid)) 3123 3124 _, err = walletInstance.verifiableClaimsToJWT(authToken, &verifiable.JWTCredClaims{}, &ProofOptions{ 3125 Controller: didKey, 3126 VerificationMethod: sampleVerificationMethod, 3127 }) 3128 require.Error(t, err) 3129 require.ErrorIs(t, err, expectErr) 3130 require.Contains(t, err.Error(), "failed to sign JWS") 3131 }) 3132 } 3133 3134 func newMockProvider(t *testing.T) *mockprovider.Provider { 3135 t.Helper() 3136 3137 loader, err := ldtestutil.DocumentLoader() 3138 require.NoError(t, err) 3139 3140 return &mockprovider.Provider{ 3141 StorageProviderValue: mockstorage.NewMockStoreProvider(), 3142 ProtocolStateStorageProviderValue: mockstorage.NewMockStoreProvider(), 3143 DocumentLoaderValue: loader, 3144 } 3145 } 3146 3147 func createSampleProfile(t *testing.T, mockctx *mockprovider.Provider) { 3148 err := CreateProfile(sampleUserID, mockctx, WithPassphrase(samplePassPhrase)) 3149 require.NoError(t, err) 3150 3151 wallet, err := New(sampleUserID, mockctx) 3152 require.NoError(t, err) 3153 require.NotEmpty(t, wallet) 3154 require.NotEmpty(t, wallet.profile.MasterLockCipher) 3155 } 3156 3157 // adds credentials to wallet and returns handle for cleanup. 3158 func addCredentialsToWallet(t *testing.T, walletInstance *Wallet, auth string, vcs ...*verifiable.Credential) func() { 3159 for _, vc := range vcs { 3160 vcBytes, err := vc.MarshalJSON() 3161 require.NoError(t, err) 3162 require.NoError(t, walletInstance.Remove(auth, Credential, vc.ID)) 3163 require.NoError(t, walletInstance.Add(auth, Credential, vcBytes)) 3164 } 3165 3166 return func() { 3167 for _, vc := range vcs { 3168 err := walletInstance.Remove(auth, Credential, vc.ID) 3169 if err != nil { 3170 t.Logf("failed to cleanup wallet instance store: %s", err) 3171 } 3172 } 3173 } 3174 } 3175 3176 const testPD = ` 3177 { 3178 "id": "32f54163-7166-48f1-93d8-ff217bdb0654", 3179 "input_descriptors": [ 3180 { 3181 "id": "type", 3182 "name": "type", 3183 "purpose": "We can only interact with specific status information for Verifiable Credentials", 3184 "schema": [ 3185 { 3186 "uri": "https://www.w3.org/2018/credentials#VerifiableCredential" 3187 } 3188 ], 3189 "constraints": { 3190 "fields": [ 3191 { 3192 "path": [ 3193 "$.credentialStatus.type", 3194 "$.vc.credentialStatus.type" 3195 ], 3196 "purpose": "We can only interact with specific status information for Verifiable Credentials", 3197 "filter": { 3198 "type": "string", 3199 "enum": [ 3200 "StatusList2021Entry", 3201 "RevocationList2021Status", 3202 "RevocationList2020Status" 3203 ] 3204 } 3205 } 3206 ] 3207 } 3208 }, 3209 { 3210 "id": "degree", 3211 "name": "degree", 3212 "purpose": "We can only hire with bachelor degree.", 3213 "schema": [ 3214 { 3215 "uri": "https://www.w3.org/2018/credentials#VerifiableCredential" 3216 } 3217 ], 3218 "constraints": { 3219 "fields": [ 3220 { 3221 "path": [ 3222 "$.credentialSubject.degree.type", 3223 "$.vc.credentialSubject.degree.type" 3224 ], 3225 "purpose": "We can only hire with bachelor degree.", 3226 "filter": { 3227 "type": "string", 3228 "const": "BachelorDegree" 3229 } 3230 } 3231 ] 3232 } 3233 } 3234 ] 3235 }` 3236 3237 //nolint:lll 3238 const testJSONLD = ` 3239 { 3240 "@context": [ 3241 "https://www.w3.org/2018/credentials/v1", 3242 "https://w3id.org/vc/status-list/2021/v1" 3243 ], 3244 "credentialStatus": { 3245 "id": "urn:uuid:1d8e36ae-6334-4bbf-bf33-8df69191b163", 3246 "statusListCredential": "http://vc-rest-echo.trustbloc.local:8075/issuer/profiles/i_myprofile_cp_p384/credentials/status/1", 3247 "statusListIndex": "28", 3248 "statusPurpose": "revocation", 3249 "type": "StatusList2021Entry" 3250 }, 3251 "credentialSubject": { 3252 "id": "did:orb:uAAA:EiBmZDwNdNMN6eh96dTakcdN8EPjmGoLHOijLw-NGY84Yg", 3253 "identifier": "3a185b8f-078a-4646-8343-76a45c2856a5", 3254 "name": "Heavy Sour Dilbit" 3255 }, 3256 "description": "Crude oil stream, produced from diluted bitumen.", 3257 "id": "urn:uuid:urn:uuid:ec57b5a1-d986-4268-9c55-de23e936aa46", 3258 "issuanceDate": "2020-05-01T00:45:04.789Z", 3259 "issuer": { 3260 "id": "did:orb:uAAA:EiA34UbWMH_0iKQfgcJ1jBPWvQvXZHuxpZ1g13PUw4xysw", 3261 "name": "i_myprofile_cp_p384" 3262 }, 3263 "name": "Heavy Sour Dilbit", 3264 "type": [ 3265 "VerifiableCredential" 3266 ] 3267 }` 3268 3269 //nolint:lll 3270 const testSDJWT = "eyJhbGciOiJFUzM4NCIsImtpZCI6ImRpZDpvcmI6dUFBQTpFaUQ2STdvMHhzUVBCakxsVXhwSC0xM3ptNkZnbXpiQWs5cHhSRlFSdTZDT2J3IzM4MzczODZjLWJiODYtNDExYS05ODljLTZmMzMwZTQ1MzQxNiJ9.eyJpYXQiOjEuNTg0Mzk4MjQ2ZSswOSwiaXNzIjoiZGlkOm9yYjp1QUFBOkVpRDZJN28weHNRUEJqTGxVeHBILTEzem02RmdtemJBazlweFJGUVJ1NkNPYnciLCJqdGkiOiJ1cm46dXVpZDp1cm46dXVpZDpkNmE3NDIyNy1iMzljLTRhOGUtOWI3OS1hNmRiNjE0MWUzNDYiLCJuYmYiOjEuNTg0Mzk4MjQ2ZSswOSwic3ViIjoiZGlkOm9yYjp1QUFBOkVpQm1aRHdOZE5NTjZlaDk2ZFRha2NkTjhFUGptR29MSE9pakx3LU5HWTg0WWciLCJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSIsImh0dHBzOi8vd3d3LnczLm9yZy8yMDE4L2NyZWRlbnRpYWxzL2V4YW1wbGVzL3YxIiwiaHR0cHM6Ly93M2MtY2NnLmdpdGh1Yi5pby92Yy1yZXZvY2F0aW9uLWxpc3QtMjAyMS9jb250ZXh0cy92MS5qc29ubGQiXSwiX3NkX2FsZyI6InNoYS0zODQiLCJjcmVkZW50aWFsU3RhdHVzIjp7ImlkIjoidXJuOnV1aWQ6NDE0YzZlNDUtNTQzZC00NDUyLWEwYzEtMGM3MWRhYjczMGY1Iiwic3RhdHVzTGlzdENyZWRlbnRpYWwiOiJodHRwOi8vdmMtcmVzdC1lY2hvLnRydXN0YmxvYy5sb2NhbDo4MDc1L2lzc3Vlci9wcm9maWxlcy9pX215cHJvZmlsZV91ZF9lczM4NF9zZGp3dC9jcmVkZW50aWFscy9zdGF0dXMvMSIsInN0YXR1c0xpc3RJbmRleCI6IjI3IiwidHlwZSI6IlJldm9jYXRpb25MaXN0MjAyMVN0YXR1cyJ9LCJjcmVkZW50aWFsU3ViamVjdCI6eyJfc2QiOlsiLWEwRmdBU3FEekZMRjg1bXc3WXFGVmh6cmlUaTFVWjV0d2V4d3otczc4ZVhUYWV1YmZ4TjVsRjFmS3FFMkRxbyIsImI2TDR2ZlFMYUNRWkZZTExfT21SeXhSQTcxVkRGMnVPMXZMdTkxbzVmTlV2YlNja0Y4X29fTU53S3RwUHBIWFIiXSwiZGVncmVlIjp7Il9zZCI6WyJZZ0RxNHNkbDdSQ3FOQnI0bTI0REhwS3RCdzZLUUk0OXhkalBWa0hhVm9DZmNtYUJiMkJlTVB4SVMwS2djcjlUIiwiNVg0czdRdkZZR2VzRmRMTjE0VjA3Zy0yUjBHWFZMWTVzNG5RclB1MFNsM3VBZHA4ZVJxTFlnX3dkLU1nLVF0XyJdfSwiaWQiOiJkaWQ6b3JiOnVBQUE6RWlCbVpEd05kTk1ONmVoOTZkVGFrY2ROOEVQam1Hb0xIT2lqTHctTkdZODRZZyJ9LCJpZCI6InVybjp1dWlkOnVybjp1dWlkOmQ2YTc0MjI3LWIzOWMtNGE4ZS05Yjc5LWE2ZGI2MTQxZTM0NiIsImlzc3VhbmNlRGF0ZSI6IjIwMjAtMDMtMTZUMjI6Mzc6MjZaIiwiaXNzdWVyIjp7ImlkIjoiZGlkOm9yYjp1QUFBOkVpRDZJN28weHNRUEJqTGxVeHBILTEzem02RmdtemJBazlweFJGUVJ1NkNPYnciLCJuYW1lIjoiaV9teXByb2ZpbGVfdWRfZXMzODRfc2Rqd3QifSwidHlwZSI6WyJWZXJpZmlhYmxlQ3JlZGVudGlhbCIsIlVuaXZlcnNpdHlEZWdyZWVDcmVkZW50aWFsIl19fQ.MGYCMQCQKQuj6IHGMSxsv_Jip3Ne8NkyqDMPcigsOk07LEBa1W9tiv_KdAcSz4LB3hM03dcCMQCiPRF2tJ0QvWXANq6QFLsGQrSLi8UyN57kOXn_WEln_JrN0BkpimA3Cx3d09e4pCU~WyJnSjBJRUxtRFpwQnFkLXJMM3I5NmN3IiwiZGVncmVlIiwiTUlUIl0~WyI2RHdTR3VqVnhCVUdwblhPRlowX0dBIiwidHlwZSIsIkJhY2hlbG9yRGVncmVlIl0~WyJ0d2ZzaXVSM00xNTNCUDB2U2ptWkd3IiwibmFtZSIsIkpheWRlbiBEb2UiXQ~WyI3Q0lzNFNPWGNnYnVjSkZONXFJdDlBIiwic3BvdXNlIiwiZGlkOmV4YW1wbGU6YzI3NmUxMmVjMjFlYmZlYjFmNzEyZWJjNmYxIl0~"