github.com/trustbloc/kms-go@v1.1.2/secretlock/local/local_secret_lock_test.go (about) 1 /* 2 Copyright SecureKey Technologies Inc. All Rights Reserved. 3 SPDX-License-Identifier: Apache-2.0 4 */ 5 6 package local 7 8 import ( 9 "bytes" 10 "crypto/rand" 11 "crypto/sha256" 12 "encoding/base64" 13 "io/ioutil" 14 "os" 15 "strings" 16 "testing" 17 18 "github.com/google/tink/go/subtle/random" 19 "github.com/stretchr/testify/require" 20 21 "github.com/trustbloc/kms-go/spi/secretlock" 22 23 "github.com/trustbloc/kms-go/secretlock/local/masterlock/hkdf" 24 "github.com/trustbloc/kms-go/secretlock/local/masterlock/pbkdf2" 25 ) 26 27 const ( 28 testKeyURI = "test://test/key/uri" 29 envPrefix = "TESTLOCAL_" 30 ) 31 32 func TestCreateServiceFromPathWithDifferentFileSizes(t *testing.T) { 33 tcs := []struct { 34 tcName string 35 fileName string 36 masterKeyLen int 37 readerError bool 38 serviceError bool 39 base64Enc bool 40 }{ 41 { 42 tcName: "large file", 43 fileName: "masterKey_file_large.txt", 44 masterKeyLen: 9999, 45 readerError: false, 46 serviceError: true, 47 }, 48 { 49 tcName: "empty file", 50 fileName: "masterKey_file_empty.txt", 51 masterKeyLen: 0, 52 readerError: true, 53 serviceError: true, 54 }, 55 { 56 tcName: "valid file with raw master key content", 57 fileName: "masterKey_file_valid_raw.txt", 58 masterKeyLen: 32, 59 readerError: false, 60 serviceError: false, 61 }, 62 { 63 tcName: "valid file with base64 URL Encoded master key", 64 fileName: "masterKey_file_valid_enc.txt", 65 masterKeyLen: 32, 66 readerError: false, 67 serviceError: false, 68 base64Enc: true, 69 }, 70 } 71 72 for _, tc := range tcs { 73 t.Run(tc.tcName, func(t *testing.T) { 74 masterKeyFilePath := tc.fileName 75 tmpfile, err := ioutil.TempFile("", masterKeyFilePath) 76 require.NoError(t, err) 77 78 defer func() { 79 // close file 80 require.NoError(t, tmpfile.Close()) 81 // clean up file 82 require.NoError(t, os.Remove(tmpfile.Name())) 83 }() 84 85 masterKeyContent := []byte{} 86 87 if tc.masterKeyLen != 0 { 88 masterKeyContent = random.GetRandomBytes(uint32(tc.masterKeyLen)) 89 require.NotEmpty(t, masterKeyContent) 90 } 91 92 if tc.base64Enc { 93 keyEncoded := base64.URLEncoding.EncodeToString(masterKeyContent) 94 masterKeyContent = []byte(keyEncoded) 95 } 96 97 n, err := tmpfile.Write(masterKeyContent) 98 require.NoError(t, err) 99 require.Equal(t, len(masterKeyContent), n) 100 101 // try to get a reader 102 r, err := MasterKeyFromPath(tmpfile.Name()) 103 if tc.readerError { 104 require.Error(t, err) 105 require.Empty(t, r) 106 107 // set r to empty reader 108 r = bytes.NewReader([]byte{}) 109 } else { 110 require.NoError(t, err) 111 require.NotEmpty(t, r) 112 } 113 114 // try to create lock service for this above reader with nil master lock (master key not encrypted) 115 s, err := NewService(r, nil) 116 if tc.serviceError { 117 require.Error(t, err) 118 require.Empty(t, s) 119 } else { 120 require.NoError(t, err) 121 require.NotEmpty(t, s) 122 } 123 }) 124 } 125 } 126 127 func TestCreateServiceFromPathWithoutMasterLock(t *testing.T) { 128 masterKeyFilePath := "masterKey_file.txt" 129 tmpfile, err := ioutil.TempFile("", masterKeyFilePath) 130 require.NoError(t, err) 131 132 defer func() { 133 // close file 134 require.NoError(t, tmpfile.Close()) 135 // clean up file 136 require.NoError(t, os.Remove(tmpfile.Name())) 137 }() 138 139 masterKeyContent := random.GetRandomBytes(uint32(32)) 140 require.NotEmpty(t, masterKeyContent) 141 142 masterKeyToSave := make([]byte, base64.URLEncoding.EncodedLen(len(masterKeyContent))) 143 base64.URLEncoding.Encode(masterKeyToSave, masterKeyContent) 144 145 n, err := tmpfile.Write(masterKeyToSave) 146 require.NoError(t, err) 147 require.Equal(t, len(masterKeyToSave), n) 148 149 // try invalid path 150 r, err := MasterKeyFromPath("bad/mk/test/file/name") 151 require.Error(t, err) 152 require.Empty(t, r) 153 154 // try real file path 155 r, err = MasterKeyFromPath(tmpfile.Name()) 156 require.NoError(t, err) 157 require.NotEmpty(t, r) 158 159 // create lock service with nil master lock (master key not encrypted) 160 s, err := NewService(r, nil) 161 require.NoError(t, err) 162 require.NotEmpty(t, s) 163 164 someKey := random.GetRandomBytes(uint32(32)) 165 someKeyEnc, err := s.Encrypt("", &secretlock.EncryptRequest{ 166 Plaintext: string(someKey), 167 }) 168 require.NoError(t, err) 169 require.NotEmpty(t, someKeyEnc) 170 171 someKeyDec, err := s.Decrypt("", &secretlock.DecryptRequest{ 172 Ciphertext: someKeyEnc.Ciphertext, 173 }) 174 require.NoError(t, err) 175 require.Equal(t, someKey, []byte(someKeyDec.Plaintext)) 176 177 // try decrypting a non valid base64URL string 178 someKeyDec, err = s.Decrypt("", &secretlock.DecryptRequest{Ciphertext: "bad{}base64URLstring[]"}) 179 require.Error(t, err) 180 require.Empty(t, someKeyDec) 181 } 182 183 func TestCreateServiceFromPathWithMasterLock(t *testing.T) { 184 // first create a master lock to use in our secret lock and encrypt the master key 185 passphrase := "secretPassphrase" 186 keySize := sha256.New().Size() 187 // salt is optional, it can be nil 188 salt := make([]byte, keySize) 189 _, err := rand.Read(salt) 190 require.NoError(t, err) 191 192 masterLockerHKDF, err := hkdf.NewMasterLock(passphrase, sha256.New, salt) 193 require.NoError(t, err) 194 require.NotEmpty(t, masterLockerHKDF) 195 196 masterLockerPBKDF2, err := pbkdf2.NewMasterLock(passphrase, sha256.New, 8192, salt) 197 require.NoError(t, err) 198 require.NotEmpty(t, masterLockerPBKDF2) 199 200 tests := []struct { 201 name string 202 masterLock secretlock.Service 203 }{ 204 { 205 name: "lock using hkdf as masterlock", 206 masterLock: masterLockerHKDF, 207 }, { 208 name: "lock using pbkdf2 as masterlock", 209 masterLock: masterLockerPBKDF2, 210 }, 211 } 212 213 for _, tt := range tests { 214 tc := tt 215 t.Run("Test "+tc.name, func(t *testing.T) { 216 checkCreateServiceUsingMasterLock(t, tc.masterLock) 217 }) 218 } 219 } 220 221 func checkCreateServiceUsingMasterLock(t *testing.T, masterLocker secretlock.Service) { 222 masterKeyFilePath := "masterKey_file.txt" 223 tmpfile, err := ioutil.TempFile("", masterKeyFilePath) 224 require.NoError(t, err) 225 226 defer func() { 227 // close file 228 require.NoError(t, tmpfile.Close()) 229 // clean up file 230 require.NoError(t, os.Remove(tmpfile.Name())) 231 }() 232 233 masterKeyContent := random.GetRandomBytes(uint32(32)) 234 require.NotEmpty(t, masterKeyContent) 235 236 // now encrypt masterKeyContent 237 masterLockEnc, err := masterLocker.Encrypt("", &secretlock.EncryptRequest{ 238 Plaintext: string(masterKeyContent), 239 }) 240 require.NoError(t, err) 241 require.NotEmpty(t, masterLockEnc) 242 243 // and write it to tmpfile 244 n, err := tmpfile.Write([]byte(masterLockEnc.Ciphertext)) 245 require.NoError(t, err) 246 require.Equal(t, len(masterLockEnc.Ciphertext), n) 247 248 // now get a reader from path 249 r, err := MasterKeyFromPath(tmpfile.Name()) 250 require.NoError(t, err) 251 require.NotEmpty(t, r) 252 253 // try a bad reader 254 badReader, err := MasterKeyFromPath("bad/mk/test/file/name") 255 require.Error(t, err) 256 require.Empty(t, badReader) 257 258 // finally create lock service with the master lock created earlier to encrypt decrypt keys using 259 // a protected (encrypted) master key 260 s, err := NewService(r, masterLocker) 261 require.NoError(t, err) 262 require.NotEmpty(t, s) 263 264 // now try to crate a lock service with a bad (nil) reader reference 265 badSerivce, err := NewService(badReader, masterLocker) 266 require.EqualError(t, err, "masterKeyReader is nil") 267 require.Empty(t, badSerivce) 268 269 // or a nil reader as argument 270 badSerivce, err = NewService(nil, masterLocker) 271 require.Error(t, err) 272 require.Empty(t, badSerivce) 273 274 // or a reader containing an invalid master key 275 badSerivce, err = NewService(bytes.NewReader([]byte("badMasterKey")), masterLocker) 276 require.Error(t, err) 277 require.Empty(t, badSerivce) 278 279 someKey := random.GetRandomBytes(uint32(32)) 280 someKeyEnc, err := s.Encrypt("", &secretlock.EncryptRequest{ 281 Plaintext: string(someKey), 282 }) 283 require.NoError(t, err) 284 require.NotEmpty(t, someKeyEnc) 285 286 someKeyDec, err := s.Decrypt("", &secretlock.DecryptRequest{ 287 Ciphertext: someKeyEnc.Ciphertext, 288 }) 289 require.NoError(t, err) 290 require.Equal(t, someKey, []byte(someKeyDec.Plaintext)) 291 292 // finally try to decrypt a bad ciphertext 293 badCipher := base64.URLEncoding.EncodeToString([]byte("BadCipherTextInAction")) 294 295 someKeyDec, err = s.Decrypt("", &secretlock.DecryptRequest{Ciphertext: badCipher}) 296 require.Error(t, err) 297 require.Empty(t, someKeyDec) 298 299 // try with a short cipher (shorter than nonce+ciphertext) 300 badCipher = base64.URLEncoding.EncodeToString([]byte("short")) 301 302 someKeyDec, err = s.Decrypt("", &secretlock.DecryptRequest{Ciphertext: badCipher}) 303 require.Error(t, err) 304 require.Empty(t, someKeyDec) 305 } 306 307 func TestCreateServiceFromEnvWithoutMasterLock(t *testing.T) { 308 masterKeyContent := random.GetRandomBytes(uint32(32)) 309 require.NotEmpty(t, masterKeyContent) 310 311 envKey := envPrefix + strings.ReplaceAll(testKeyURI, "/", "_") 312 313 // set the master key (unencrypted) in env 314 err := os.Setenv(envKey, base64.URLEncoding.EncodeToString(masterKeyContent)) 315 require.NoError(t, err) 316 317 defer func() { 318 // clean up env variable 319 require.NoError(t, os.Unsetenv(envKey)) 320 }() 321 322 r, err := MasterKeyFromEnv(envPrefix, "bad/mk/test/key") 323 require.Error(t, err) 324 require.Empty(t, r) 325 326 r, err = MasterKeyFromEnv(envPrefix, testKeyURI) 327 require.NoError(t, err) 328 require.NotEmpty(t, r) 329 330 // create lock service with nil master lock (master key not encrypted) 331 s, err := NewService(r, nil) 332 require.NoError(t, err) 333 require.NotEmpty(t, s) 334 335 someKey := random.GetRandomBytes(uint32(32)) 336 someKeyEnc, err := s.Encrypt("", &secretlock.EncryptRequest{ 337 Plaintext: string(someKey), 338 }) 339 require.NoError(t, err) 340 require.NotEmpty(t, someKeyEnc) 341 342 someKeyDec, err := s.Decrypt("", &secretlock.DecryptRequest{ 343 Ciphertext: someKeyEnc.Ciphertext, 344 }) 345 require.NoError(t, err) 346 require.Equal(t, someKey, []byte(someKeyDec.Plaintext)) 347 } 348 349 func TestCreateServiceFromEnvWithMasterLock(t *testing.T) { 350 masterKeyContent := random.GetRandomBytes(uint32(32)) 351 require.NotEmpty(t, masterKeyContent) 352 353 // first create a master lock to use in our secret lock and encrypt the master key 354 passphrase := "secretPassphrase" 355 keySize := sha256.New().Size() 356 // salt is optional, it can be nil 357 salt := make([]byte, keySize) 358 _, err := rand.Read(salt) 359 require.NoError(t, err) 360 361 masterLocker, err := hkdf.NewMasterLock(passphrase, sha256.New, salt) 362 require.NoError(t, err) 363 require.NotEmpty(t, masterLocker) 364 365 // now encrypt masterKeyContent 366 masterLockEnc, err := masterLocker.Encrypt("", &secretlock.EncryptRequest{ 367 Plaintext: string(masterKeyContent), 368 }) 369 require.NoError(t, err) 370 require.NotEmpty(t, masterLockEnc) 371 372 envKey := envPrefix + strings.ReplaceAll(testKeyURI, "/", "_") 373 374 // now set the encrypted master key in env 375 err = os.Setenv(envKey, masterLockEnc.Ciphertext) 376 require.NoError(t, err) 377 378 defer func() { 379 // clean up env variable 380 require.NoError(t, os.Unsetenv(envKey)) 381 }() 382 383 // get a reader from an invalid env variable 384 badReader, err := MasterKeyFromEnv(envPrefix, "bad/mk/test/key") 385 require.Error(t, err) 386 require.Empty(t, badReader) 387 388 // get a reader from a valid env variable 389 r, err := MasterKeyFromEnv(envPrefix, testKeyURI) 390 require.NoError(t, err) 391 require.NotEmpty(t, r) 392 393 // finally create lock service with the master lock created earlier to encrypt decrypt keys using 394 // a protected (encrypted) master key 395 s, err := NewService(r, masterLocker) 396 require.NoError(t, err) 397 require.NotEmpty(t, s) 398 399 // now try to crate a lock service with a bad reader 400 badSerivce, err := NewService(badReader, masterLocker) 401 require.Error(t, err) 402 require.Empty(t, badSerivce) 403 404 // or a nil reader 405 badSerivce, err = NewService(nil, masterLocker) 406 require.Error(t, err) 407 require.Empty(t, badSerivce) 408 409 someKey := random.GetRandomBytes(uint32(32)) 410 someKeyEnc, err := s.Encrypt("", &secretlock.EncryptRequest{ 411 Plaintext: string(someKey), 412 }) 413 require.NoError(t, err) 414 require.NotEmpty(t, someKeyEnc) 415 416 someKeyDec, err := s.Decrypt("", &secretlock.DecryptRequest{ 417 Ciphertext: someKeyEnc.Ciphertext, 418 }) 419 require.NoError(t, err) 420 require.Equal(t, someKey, []byte(someKeyDec.Plaintext)) 421 }