| // Copyright 2022 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| package cryptohome |
| |
| import ( |
| "bytes" |
| "context" |
| "io/ioutil" |
| "os" |
| "path" |
| "path/filepath" |
| "time" |
| |
| "chromiumos/tast/common/hwsec" |
| "chromiumos/tast/ctxutil" |
| "chromiumos/tast/local/cryptohome" |
| hwseclocal "chromiumos/tast/local/hwsec" |
| "chromiumos/tast/testing" |
| ) |
| |
| func init() { |
| testing.AddTest(&testing.Test{ |
| Func: UserSecretStashAddPin, |
| Desc: "Test user secret stash basic add pin flow with password", |
| Contacts: []string{ |
| "hardikgoyal@chromium.org", |
| "cryptohome-core@chromium.org", |
| }, |
| Attr: []string{"group:mainline", "informational"}, |
| SoftwareDeps: []string{"pinweaver", "reboot"}, |
| }) |
| } |
| |
| func UserSecretStashAddPin(ctx context.Context, s *testing.State) { |
| const ( |
| userName = "foo@bar.baz" |
| userPassword = "secret" |
| userPin = "123456" |
| passwordLabel = "online-password" |
| pinLabel = "test-pin" |
| testFile = "file" |
| testFileContent = "content" |
| ussFlagFile = "/var/lib/cryptohome/uss_enabled" |
| ) |
| |
| ctxForCleanUp := ctx |
| ctx, cancel := ctxutil.Shorten(ctx, 10*time.Second) |
| defer cancel() |
| |
| cmdRunner := hwseclocal.NewCmdRunner() |
| client := hwsec.NewCryptohomeClient(cmdRunner) |
| helper, err := hwseclocal.NewHelper(cmdRunner) |
| if err != nil { |
| s.Fatal("Failed to create hwsec local helper: ", err) |
| } |
| daemonController := helper.DaemonController() |
| |
| // Wait for cryptohomed becomes available if needed. |
| if err := daemonController.Ensure(ctx, hwsec.CryptohomeDaemon); err != nil { |
| s.Fatal("Failed to ensure cryptohomed: ", err) |
| } |
| |
| // Clean up obsolete state, in case there's any. |
| if err := client.UnmountAll(ctx); err != nil { |
| s.Fatal("Failed to unmount vaults for preparation: ", err) |
| } |
| if err := cryptohome.RemoveVault(ctx, userName); err != nil { |
| s.Fatal("Failed to remove old vault for preparation: ", err) |
| } |
| |
| // Enable the UserSecretStash experiment for the duration of the test by |
| // creating a flag file that's checked by cryptohomed. |
| if err := os.MkdirAll(path.Dir(ussFlagFile), 0755); err != nil { |
| s.Fatal("Failed to create the UserSecretStash flag file directory: ", err) |
| } |
| if err := ioutil.WriteFile(ussFlagFile, []byte{}, 0644); err != nil { |
| s.Fatal("Failed to write the UserSecretStash flag file: ", err) |
| } |
| defer os.Remove(ussFlagFile) |
| |
| // Create and mount the persistent user. |
| authSessionID, err := client.StartAuthSession(ctx, userName /*ephemeral=*/, false) |
| if err != nil { |
| s.Fatal("Failed to start auth session: ", err) |
| } |
| if err := client.CreatePersistentUser(ctx, authSessionID); err != nil { |
| s.Fatal("Failed to create persistent user: ", err) |
| } |
| defer cryptohome.RemoveVault(ctxForCleanUp, userName) |
| if err := client.PreparePersistentVault(ctx, authSessionID /*ecryptfs=*/, false); err != nil { |
| s.Fatal("Failed to prepare new persistent vault: ", err) |
| } |
| defer client.UnmountAll(ctxForCleanUp) |
| |
| // Write a test file to verify persistence. |
| userPath, err := cryptohome.UserPath(ctx, userName) |
| if err != nil { |
| s.Fatal("Failed to get user vault path: ", err) |
| } |
| filePath := filepath.Join(userPath, testFile) |
| if err := ioutil.WriteFile(filePath, []byte(testFileContent), 0644); err != nil { |
| s.Fatal("Failed to write a file to the vault: ", err) |
| } |
| |
| // Add a password auth factor to the user. |
| if err := client.AddAuthFactor(ctx, authSessionID, passwordLabel, userPassword); err != nil { |
| s.Fatal("Failed to add a password authfactor: ", err) |
| } |
| |
| // Unmount the user. |
| if err := client.UnmountAll(ctx); err != nil { |
| s.Fatal("Failed to unmount vaults for re-mounting: ", err) |
| } |
| |
| // Authenticate a new auth session via the auth factor, mount the user and add a pin. |
| authSessionID, err = client.StartAuthSession(ctx, userName /*ephemeral=*/, false) |
| if err != nil { |
| s.Fatal("Failed to start auth session for re-mounting: ", err) |
| } |
| if err := client.AuthenticateAuthFactor(ctx, authSessionID, passwordLabel, userPassword); err != nil { |
| s.Fatal("Failed to authenticate with auth session: ", err) |
| } |
| if err := client.PreparePersistentVault(ctx, authSessionID /*ecryptfs=*/, false); err != nil { |
| s.Fatal("Failed to prepare persistent vault: ", err) |
| } |
| |
| // Verify that the test file is still there. |
| if content, err := ioutil.ReadFile(filePath); err != nil { |
| s.Fatal("Failed to read back test file: ", err) |
| } else if bytes.Compare(content, []byte(testFileContent)) != 0 { |
| s.Fatalf("Incorrect tests file content. got: %q, want: %q", content, testFileContent) |
| } |
| |
| // Add a pin auth factor to the user. |
| if err := client.AddPinAuthFactor(ctx, authSessionID, pinLabel, userPin); err != nil { |
| s.Fatal("Failed to create persistent user: ", err) |
| } |
| |
| // Unmount the user. |
| if err := client.UnmountAll(ctx); err != nil { |
| s.Fatal("Failed to unmount vaults for re-mounting: ", err) |
| } |
| |
| // Authenticate a new auth session via the new added pin auth factor and mount the user. |
| authSessionID, err = client.StartAuthSession(ctx, userName /*ephemeral=*/, false) |
| if err != nil { |
| s.Fatal("Failed to start auth session for re-mounting: ", err) |
| } |
| if err := client.AuthenticatePinAuthFactor(ctx, authSessionID, pinLabel, userPin); err != nil { |
| s.Fatal("Failed to authenticate with auth session: ", err) |
| } |
| if err := client.PreparePersistentVault(ctx, authSessionID /*ecryptfs=*/, false); err != nil { |
| s.Fatal("Failed to prepare persistent vault: ", err) |
| } |
| |
| // Verify that the test file is still there. |
| if content, err := ioutil.ReadFile(filePath); err != nil { |
| s.Fatal("Failed to read back test file: ", err) |
| } else if bytes.Compare(content, []byte(testFileContent)) != 0 { |
| s.Fatalf("Incorrect tests file content. got: %q, want: %q", content, testFileContent) |
| } |
| } |