github.com/hyperledger/aries-framework-go@v0.3.2/pkg/wallet/kmsclient_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/sha256" 11 "errors" 12 "testing" 13 "time" 14 15 "github.com/google/uuid" 16 "github.com/stretchr/testify/require" 17 18 kmsapi "github.com/hyperledger/aries-framework-go/pkg/kms" 19 mockcrypto "github.com/hyperledger/aries-framework-go/pkg/mock/crypto" 20 mockkms "github.com/hyperledger/aries-framework-go/pkg/mock/kms" 21 mockstorage "github.com/hyperledger/aries-framework-go/pkg/mock/storage" 22 "github.com/hyperledger/aries-framework-go/pkg/secretlock/local/masterlock/pbkdf2" 23 ) 24 25 const ( 26 samplePassPhrase = "fakepassphrase" 27 sampleRemoteKMSAuth = "sample-auth-token" 28 sampleKeyMgrErr = "sample-keymgr-err" 29 ) 30 31 func TestKeyManagerStore(t *testing.T) { 32 t.Run("test key manager instance", func(t *testing.T) { 33 require.NotEmpty(t, keyManager()) 34 require.Equal(t, keyManager(), keyManager()) 35 }) 36 } 37 38 func TestKeyManager(t *testing.T) { 39 t.Run("create key manager for localkms - with passphrase", func(t *testing.T) { 40 sampleUser := uuid.New().String() 41 masterLock, err := getDefaultSecretLock(samplePassPhrase) 42 require.NoError(t, err) 43 44 masterLockCipherText, err := createMasterLock(masterLock) 45 require.NoError(t, err) 46 require.NotEmpty(t, masterLockCipherText) 47 48 profileInfo := &profile{ 49 User: sampleUser, 50 MasterLockCipher: masterLockCipherText, 51 } 52 53 kmsStore, err := kmsapi.NewAriesProviderWrapper(mockstorage.NewMockStoreProvider()) 54 require.NoError(t, err) 55 56 kmgr, err := keyManager().createKeyManager(profileInfo, kmsStore, 57 &unlockOpts{passphrase: samplePassPhrase}) 58 require.NoError(t, err) 59 require.NotEmpty(t, kmgr) 60 }) 61 62 t.Run("create key manager for localkms - with secret lock service", func(t *testing.T) { 63 sampleUser := uuid.New().String() 64 masterLock, err := pbkdf2.NewMasterLock(samplePassPhrase, sha256.New, 0, nil) 65 require.NoError(t, err) 66 67 masterLockCipherText, err := createMasterLock(masterLock) 68 require.NoError(t, err) 69 require.NotEmpty(t, masterLockCipherText) 70 71 profileInfo := &profile{ 72 User: sampleUser, 73 MasterLockCipher: masterLockCipherText, 74 } 75 76 kmsStore, err := kmsapi.NewAriesProviderWrapper(mockstorage.NewMockStoreProvider()) 77 require.NoError(t, err) 78 79 kmgr, err := keyManager().createKeyManager(profileInfo, kmsStore, 80 &unlockOpts{secretLockSvc: masterLock}) 81 require.NoError(t, err) 82 require.NotEmpty(t, kmgr) 83 }) 84 85 t.Run("create key manager for localkms - passphrase missmatch", func(t *testing.T) { 86 sampleUser := uuid.New().String() 87 masterLock, err := getDefaultSecretLock(samplePassPhrase) 88 require.NoError(t, err) 89 90 masterLockCipherText, err := createMasterLock(masterLock) 91 require.NoError(t, err) 92 require.NotEmpty(t, masterLockCipherText) 93 94 profileInfo := &profile{ 95 User: sampleUser, 96 MasterLockCipher: masterLockCipherText, 97 } 98 99 kmsStore, err := kmsapi.NewAriesProviderWrapper(mockstorage.NewMockStoreProvider()) 100 require.NoError(t, err) 101 102 // use wrong passphrase 103 kmgr, err := keyManager().createKeyManager(profileInfo, kmsStore, 104 &unlockOpts{passphrase: samplePassPhrase + "wrong"}) 105 require.Empty(t, kmgr) 106 require.Error(t, err) 107 require.Contains(t, err.Error(), "message authentication failed") 108 }) 109 110 t.Run("create key manager for localkms - secret lock service missmatch", func(t *testing.T) { 111 sampleUser := uuid.New().String() 112 masterLock, err := pbkdf2.NewMasterLock(samplePassPhrase, sha256.New, 0, nil) 113 require.NoError(t, err) 114 115 masterLockCipherText, err := createMasterLock(masterLock) 116 require.NoError(t, err) 117 require.NotEmpty(t, masterLockCipherText) 118 119 profileInfo := &profile{ 120 User: sampleUser, 121 MasterLockCipher: masterLockCipherText, 122 } 123 124 // use wrong secret lock service 125 masterLockBad, err := pbkdf2.NewMasterLock(samplePassPhrase+"wrong", sha256.New, 0, nil) 126 require.NoError(t, err) 127 128 kmsStore, err := kmsapi.NewAriesProviderWrapper(mockstorage.NewMockStoreProvider()) 129 require.NoError(t, err) 130 131 kmgr, err := keyManager().createKeyManager(profileInfo, kmsStore, 132 &unlockOpts{secretLockSvc: masterLockBad}) 133 require.Empty(t, kmgr) 134 require.Error(t, err) 135 require.Contains(t, err.Error(), "message authentication failed") 136 }) 137 138 t.Run("create key manager for remotekms", func(t *testing.T) { 139 sampleUser := uuid.New().String() 140 profileInfo := &profile{ 141 User: sampleUser, 142 KeyServerURL: sampleKeyServerURL, 143 } 144 145 kmsStore, err := kmsapi.NewAriesProviderWrapper(mockstorage.NewMockStoreProvider()) 146 require.NoError(t, err) 147 148 kmgr, err := keyManager().createKeyManager(profileInfo, kmsStore, 149 &unlockOpts{authToken: sampleRemoteKMSAuth}) 150 require.NoError(t, err) 151 require.NotEmpty(t, kmgr) 152 153 _, _, err = kmgr.Create(kmsapi.ED25519Type) 154 require.Error(t, err) 155 }) 156 157 t.Run("create key manager for failure - invalid profile", func(t *testing.T) { 158 profileInfo := &profile{ 159 User: uuid.New().String(), 160 } 161 162 kmsStore, err := kmsapi.NewAriesProviderWrapper(mockstorage.NewMockStoreProvider()) 163 require.NoError(t, err) 164 165 kmgr, err := keyManager().createKeyManager(profileInfo, kmsStore, 166 &unlockOpts{authToken: sampleRemoteKMSAuth}) 167 require.Empty(t, kmgr) 168 require.Error(t, err) 169 require.Contains(t, err.Error(), "invalid wallet profile") 170 }) 171 } 172 173 func TestImportKeyJWK(t *testing.T) { 174 sampleUser := uuid.New().String() 175 masterLock, err := getDefaultSecretLock(samplePassPhrase) 176 require.NoError(t, err) 177 178 masterLockCipherText, err := createMasterLock(masterLock) 179 require.NoError(t, err) 180 require.NotEmpty(t, masterLockCipherText) 181 182 profileInfo := &profile{ 183 User: sampleUser, 184 MasterLockCipher: masterLockCipherText, 185 } 186 187 kmsStore, err := kmsapi.NewAriesProviderWrapper(mockstorage.NewMockStoreProvider()) 188 require.NoError(t, err) 189 190 kmgr, err := keyManager().createKeyManager(profileInfo, kmsStore, 191 &unlockOpts{passphrase: samplePassPhrase}) 192 require.NoError(t, err) 193 require.NotEmpty(t, kmgr) 194 195 tkn, err := sessionManager().createSession(uuid.New().String(), kmgr, 0) 196 require.NoError(t, err) 197 198 t.Run("test successful jwk key imports", func(t *testing.T) { 199 tests := []struct { 200 name string 201 sampleJWK []byte 202 ID string 203 error string 204 }{ 205 { 206 name: "import Ed25519", 207 sampleJWK: []byte(`{ 208 "kty": "OKP", 209 "d":"Dq5t2WS3OMzcpkh8AyVxJs5r9v4L39ocIz9CpUOqM40", 210 "crv": "Ed25519", 211 "x": "ODaPFurJgFcoVCUYEmgOJpWOtPlOYbHSugasscKWqDM", 212 "kid":"z6MkiEh8RQL83nkPo8ehDeE7" 213 }`), 214 ID: "did:example:123#z6MkiEh8RQL83nkPo8ehDeE7", 215 }, 216 { 217 name: "import Ed25519, use document id for missing kid", 218 sampleJWK: []byte(`{ 219 "kty": "OKP", 220 "d":"Dq5t2WS3OMzcpkh8AyVxJs5r9v4L39ocIz9CpUOqM40", 221 "crv": "Ed25519", 222 "x": "ODaPFurJgFcoVCUYEmgOJpWOtPlOYbHSugasscKWqDM" 223 }`), 224 ID: "did:example:123#z6MkiEh8RQL83nkPo8ehDeE8", 225 }, 226 { 227 name: "import P-256", 228 sampleJWK: []byte(`{ 229 "kty": "EC", 230 "kid": "z6MkiEh8RQL83nkPo8ehDeE9", 231 "crv": "P-256", 232 "alg": "EdDSA", 233 "x": "POTofegIPtEJ4ctuYJ9qY1GZepxAqEcx-RjoYJghW5U", 234 "y": "C0STSwXZ-krV5CYdqU4yKh7NiKKjwmAkIMXfeyo3Irw", 235 "d": "GeJ0tppbkfJl8Jci00L3WBIopiE6p6cnkPdT_l9xKmk" 236 }`), 237 ID: "did:example:123#z6MkiEh8RQL83nkPo8ehDeE9", 238 }, 239 { 240 name: "import P-384", 241 sampleJWK: []byte(`{ 242 "kty": "EC", 243 "crv": "P-384", 244 "x": "eQbMauiHc9HuiqXT894gW5XTCrOpeY8cjLXAckfRtdVBLzVHKaiXAAxBFeVrSB75", 245 "y": "YOjxhMkdH9QnNmGCGuGXJrjAtk8CQ1kTmEEi9cg2R9ge-zh8SFT1Xu6awoUjK5Bv", 246 "d": "dXghMAzYZmv46SNRuxmfDIuAlv7XIhvlkPzW3vXsopB1ihWp47tx0hqjZmYO6fJa" 247 }`), 248 ID: "did:example:123#z6MkiEh8RQL83nkPo8ehDeE10", 249 }, 250 { 251 name: "import Ed25519 failure - invalid jwk", 252 sampleJWK: []byte(`{ 253 "invalid":"test" 254 }`), 255 ID: "did:example:123#z6MkiEh8RQL83nkPo8ehDeE7", 256 error: " unknown json web key type", 257 }, 258 { 259 name: "import secp256k1 failure - unsupported curve", 260 sampleJWK: []byte(`{ 261 "kty": "EC", 262 "crv": "secp256k1", 263 "x": "GBMxavme-AfIVDKqI6WBJ4V5wZItsxJ9muhxPByllHQ", 264 "y": "SChlfVBhTXG_sRGc9ZdFeCYzI3Kbph3ivE12OFVk4jo", 265 "d": "m5N7gTItgWz6udWjuqzJsqX-vksUnxJrNjD5OilScBc" 266 }`), 267 ID: "did:example:123#z6MkiEh8RQL83nkPo8ehDeE7", 268 error: "unsupported Key type secp256k1", 269 }, 270 { 271 name: "import Ed25519 failure - incorrect key type", 272 sampleJWK: []byte(`{ 273 "kty": "OKP", 274 "crv": "Ed25519", 275 "x": "VCpo2LMLhn6iWku8MKvSLg2ZAoC-nlOyPVQaO3FxVeQ" 276 }`), 277 ID: "did:example:123#z6MkiEh8RQL83nkPo8ehDeE7", 278 error: "mport private key does not support this key type or key is public", 279 }, 280 } 281 282 t.Parallel() 283 284 for _, test := range tests { 285 tc := test 286 t.Run(tc.name, func(t *testing.T) { 287 if tc.error != "" { 288 err := importKeyJWK(tkn, &keyContent{PrivateKeyJwk: tc.sampleJWK, ID: tc.ID}) 289 require.Error(t, err) 290 require.Contains(t, err.Error(), tc.error) 291 292 return 293 } 294 295 err := importKeyJWK(tkn, &keyContent{PrivateKeyJwk: tc.sampleJWK, ID: tc.ID}) 296 require.NoError(t, err) 297 298 handle, err := kmgr.Get(getKID(tc.ID)) 299 require.NoError(t, err) 300 require.NotEmpty(t, handle) 301 }) 302 } 303 }) 304 305 t.Run("test key ID already exists", func(t *testing.T) { 306 err := importKeyJWK(tkn, &keyContent{PrivateKeyJwk: []byte(`{ 307 "kty": "OKP", 308 "d":"Dq5t2WS3OMzcpkh8AyVxJs5r9v4L39ocIz9CpUOqM40", 309 "crv": "Ed25519", 310 "x": "ODaPFurJgFcoVCUYEmgOJpWOtPlOYbHSugasscKWqDM", 311 "kid":"z6MkiEh8RQL83nkPo8ehDeX7" 312 }`), ID: "did:example:123#z6MkiEh8RQL83nkPo8ehDeX7"}) 313 require.NoError(t, err) 314 315 // import different key with same key ID 316 err = importKeyJWK(tkn, &keyContent{PrivateKeyJwk: []byte(`{ 317 "kty": "EC", 318 "crv": "P-384", 319 "x": "eQbMauiHc9HuiqXT894gW5XTCrOpeY8cjLXAckfRtdVBLzVHKaiXAAxBFeVrSB75", 320 "y": "YOjxhMkdH9QnNmGCGuGXJrjAtk8CQ1kTmEEi9cg2R9ge-zh8SFT1Xu6awoUjK5Bv", 321 "d": "dXghMAzYZmv46SNRuxmfDIuAlv7XIhvlkPzW3vXsopB1ihWp47tx0hqjZmYO6fJa", 322 "kid": "z6MkiEh8RQL83nkPo8ehDeX7" 323 }`), ID: "did:example:123#z6MkiEh8RQL83nkPo8ehDeX8"}) 324 require.Error(t, err) 325 require.Contains(t, err.Error(), "requested ID 'z6MkiEh8RQL83nkPo8ehDeX7' already exists") 326 327 // import different key with same content ID (missing kid) 328 err = importKeyJWK(tkn, &keyContent{PrivateKeyJwk: []byte(`{ 329 "kty": "EC", 330 "crv": "P-384", 331 "x": "eQbMauiHc9HuiqXT894gW5XTCrOpeY8cjLXAckfRtdVBLzVHKaiXAAxBFeVrSB75", 332 "y": "YOjxhMkdH9QnNmGCGuGXJrjAtk8CQ1kTmEEi9cg2R9ge-zh8SFT1Xu6awoUjK5Bv", 333 "d": "dXghMAzYZmv46SNRuxmfDIuAlv7XIhvlkPzW3vXsopB1ihWp47tx0hqjZmYO6fJa" 334 }`), ID: "did:example:123#z6MkiEh8RQL83nkPo8ehDeX7"}) 335 require.Error(t, err) 336 require.Contains(t, err.Error(), "requested ID 'z6MkiEh8RQL83nkPo8ehDeX7' already exists") 337 338 // no KID 339 err = importKeyJWK(tkn, &keyContent{PrivateKeyJwk: []byte(`{ 340 "kty": "OKP", 341 "d":"Dq5t2WS3OMzcpkh8AyVxJs5r9v4L39ocIz9CpUOqM40", 342 "crv": "Ed25519", 343 "x": "ODaPFurJgFcoVCUYEmgOJpWOtPlOYbHSugasscKWqDM" 344 }`)}) 345 require.NoError(t, err) 346 }) 347 348 t.Run("test key manager errors", func(t *testing.T) { 349 err := importKeyJWK(tkn+"invalid", &keyContent{PrivateKeyJwk: []byte(`{ 350 "kty": "OKP", 351 "d":"Dq5t2WS3OMzcpkh8AyVxJs5r9v4L39ocIz9CpUOqM40", 352 "crv": "Ed25519", 353 "x": "ODaPFurJgFcoVCUYEmgOJpWOtPlOYbHSugasscKWqDM", 354 "kid":"z6MkiEh8RQL83nkPo8ehDeX7" 355 }`), ID: "did:example:123#z6MkiEh8RQL83nkPo8ehDeX7"}) 356 require.True(t, errors.Is(err, ErrWalletLocked)) 357 }) 358 } 359 360 func TestImportKeyBase58(t *testing.T) { 361 sampleUser := uuid.New().String() 362 masterLock, e := getDefaultSecretLock(samplePassPhrase) 363 require.NoError(t, e) 364 365 masterLockCipherText, e := createMasterLock(masterLock) 366 require.NoError(t, e) 367 require.NotEmpty(t, masterLockCipherText) 368 369 profileInfo := &profile{ 370 User: sampleUser, 371 MasterLockCipher: masterLockCipherText, 372 } 373 374 kmsStore, err := kmsapi.NewAriesProviderWrapper(mockstorage.NewMockStoreProvider()) 375 require.NoError(t, err) 376 377 kmgr, e := keyManager().createKeyManager(profileInfo, kmsStore, 378 &unlockOpts{passphrase: samplePassPhrase}) 379 require.NoError(t, e) 380 require.NotEmpty(t, kmgr) 381 382 tkn, e := sessionManager().createSession(uuid.New().String(), kmgr, 0) 383 require.NoError(t, e) 384 require.NotEmpty(t, tkn) 385 386 t.Run("test successful base58 key imports", func(t *testing.T) { 387 tests := []struct { 388 name string 389 keyBase58 string 390 keyType string 391 ID string 392 error string 393 }{ 394 { 395 name: "import Ed25519VerificationKey2018", 396 keyBase58: "zJRjGFZydU5DBdS2p5qbiUzDFAxbXTkjiDuGPksMBbY5TNyEsGfK4a4WGKjBCh1zeNryeuKtPotp8W1ESnwP71y", 397 keyType: "Ed25519VerificationKey2018", 398 ID: "did:example:123#z6MkiEh8RQL83nkPo8ehDeE1", 399 }, 400 { 401 name: "import Bls12381G1Key2020", 402 keyBase58: "6gsgGpdx7p1nYoKJ4b5fKt1xEomWdnemg9nJFX6mqNCh", 403 keyType: "Bls12381G1Key2020", 404 ID: "did:example:123#z6MkiEh8RQL83nkPo8ehDeE2", 405 }, 406 { 407 name: "import Ed25519VerificationKey2018 failure", 408 keyBase58: "6gsgGpdx7p1nYoKJ4b5fKt1xEomWdnemg9nJFX6mqNCh", 409 keyType: "GpgVerificationKey2020", 410 ID: "did:example:123#z6MkiEh8RQL83nkPo8ehDeE3", 411 error: "only Ed25519VerificationKey2018 & Bls12381G1Key2020 are supported in base58 format", 412 }, 413 { 414 name: "import Bls12381G1Key2020", 415 keyBase58: "6gsgGpdx7p1nYossKJ4b5fKt1xEomWdnemg9nJFX6mqNCh", 416 keyType: "Bls12381G1Key2020", 417 ID: "did:example:123#z6MkiEh8RQL83nkPo8ehDeE2", 418 error: "invalid size of private key", 419 }, 420 } 421 422 t.Parallel() 423 424 for _, test := range tests { 425 tc := test 426 t.Run(tc.name, func(t *testing.T) { 427 if tc.error != "" { 428 err := importKeyBase58(tkn, &keyContent{ 429 ID: tc.ID, 430 PrivateKeyBase58: tc.keyBase58, 431 KeyType: tc.keyType, 432 }) 433 require.Error(t, err) 434 require.Contains(t, err.Error(), tc.error) 435 436 return 437 } 438 439 err := importKeyBase58(tkn, &keyContent{ 440 ID: tc.ID, 441 PrivateKeyBase58: tc.keyBase58, 442 KeyType: tc.keyType, 443 }) 444 require.NoError(t, err) 445 446 handle, err := kmgr.Get(getKID(tc.ID)) 447 require.NoError(t, err) 448 require.NotEmpty(t, handle) 449 }) 450 } 451 }) 452 453 t.Run("test key ID already exists", func(t *testing.T) { 454 err := importKeyBase58(tkn, &keyContent{ 455 ID: "did:example:123#z6MkiEh8RQL83nkPo8ehDeE4", 456 PrivateKeyBase58: "zJRjGFZydU5DBdS2p5qbiUzDFAxbXTkjiDuGPksMBbY5TNyEsGfK4a4WGKjBCh1zeNryeuKtPotp8W1ESnwP71y", 457 KeyType: "Ed25519VerificationKey2018", 458 }) 459 require.NoError(t, err) 460 461 err = importKeyBase58(tkn, &keyContent{ 462 ID: "did:example:123#z6MkiEh8RQL83nkPo8ehDeE4", 463 PrivateKeyBase58: "zJRjGFZydU5DBdS2p5qbiUzDFAxbXTkjiDuGPksMBbY5TNyEsGfK4a4WGKjBCh1zeNryeuKtPotp8W1ESnwP71y", 464 KeyType: "Ed25519VerificationKey2018", 465 }) 466 require.Error(t, err) 467 require.Contains(t, err.Error(), "requested ID 'z6MkiEh8RQL83nkPo8ehDeE4' already exists") 468 }) 469 470 t.Run("test key manager errors", func(t *testing.T) { 471 err := importKeyBase58(tkn+"invalid", &keyContent{ 472 ID: "did:example:123#z6MkiEh8RQL83nkPo8ehDeE5", 473 PrivateKeyBase58: "zJRjGFZydU5DBdS2p5qbiUzDFAxbXTkjiDuGPksMBbY5TNyEsGfK4a4WGKjBCh1zeNryeuKtPotp8W1ESnwP71y", 474 KeyType: "Ed25519VerificationKey2018", 475 }) 476 require.True(t, errors.Is(err, ErrWalletLocked)) 477 }) 478 479 t.Run("test import errors", func(t *testing.T) { 480 sampleErr := errors.New(sampleKeyMgrErr) 481 482 tkn, err := sessionManager().createSession(uuid.New().String(), 483 &mockkms.KeyManager{ImportPrivateKeyErr: sampleErr}, 0) 484 require.NoError(t, err) 485 require.NotEmpty(t, tkn) 486 487 require.NoError(t, err) 488 489 err = importKeyBase58(tkn, &keyContent{ 490 ID: "did:example:123#z6MkiEh8RQL83nkPo8ehDeE5", 491 PrivateKeyBase58: "zJRjGFZydU5DBdS2p5qbiUzDFAxbXTkjiDuGPksMBbY5TNyEsGfK4a4WGKjBCh1zeNryeuKtPotp8W1ESnwP71y", 492 KeyType: "Ed25519VerificationKey2018", 493 }) 494 require.Error(t, err) 495 require.True(t, errors.Is(err, sampleErr)) 496 497 err = importKeyBase58(tkn, &keyContent{ 498 ID: "did:example:123#z6MkiEh8RQL83nkPo8ehDeE5", 499 PrivateKeyBase58: "6gsgGpdx7p1nYoKJ4b5fKt1xEomWdnemg9nJFX6mqNCh", 500 KeyType: "Bls12381G1Key2020", 501 }) 502 require.Error(t, err) 503 require.True(t, errors.Is(err, sampleErr)) 504 }) 505 } 506 507 func TestKMSSigner(t *testing.T) { 508 token, err := sessionManager().createSession(uuid.New().String(), 509 &mockkms.KeyManager{}, 500*time.Millisecond) 510 require.NoError(t, err) 511 512 t.Run("kms signer initialization success", func(t *testing.T) { 513 signer, err := newKMSSigner(token, &mockcrypto.Crypto{SignErr: errors.New(sampleKeyMgrErr)}, &ProofOptions{ 514 VerificationMethod: "did:example#123", 515 }) 516 require.NoError(t, err) 517 require.NotNil(t, signer) 518 }) 519 520 t.Run("kms signer initialization errors", func(t *testing.T) { 521 // invalid auth 522 signer, err := newKMSSigner("invalid", &mockcrypto.Crypto{}, &ProofOptions{}) 523 require.True(t, errors.Is(err, ErrWalletLocked)) 524 require.Empty(t, signer) 525 526 // invalid verification method 527 signer, err = newKMSSigner(token, &mockcrypto.Crypto{}, &ProofOptions{ 528 VerificationMethod: "invalid", 529 }) 530 require.Error(t, err) 531 require.Contains(t, err.Error(), "invalid verification method format") 532 require.Empty(t, signer) 533 }) 534 }