1// Copyright 2019 Keybase, Inc. All rights reserved. Use of
2// this source code is governed by the included BSD license.
3
4// +build linux,!skipkeyringtests
5
6package libkb
7
8import (
9	"fmt"
10	"os"
11	"testing"
12
13	secsrv "github.com/keybase/go-keychain/secretservice"
14	"github.com/stretchr/testify/require"
15)
16
17func secret() LKSecFullSecret {
18	sec, err := newLKSecFullSecretFromBytes([]byte("YELLOW_SUBMARINEYELLOW_SUBMARINE"))
19	if err != nil {
20		panic(err)
21	}
22	return sec
23}
24
25func requireError(t *testing.T, err error, msg string) {
26	require.Error(t, err)
27	require.Contains(t, err.Error(), msg)
28}
29
30var alice = NewNormalizedUsername("alice")
31var bob = NewNormalizedUsername("bob")
32var charlie = NewNormalizedUsername("charlie")
33
34func TestSSSSBasic(t *testing.T) {
35	t.Skip("Skipping secret service test while Linux CI AMI is being upgraded to include keyring")
36
37	tc := SetupTest(t, "secret_store_secretservice", 0)
38	defer tc.Cleanup()
39	mctx := NewMetaContextForTest(tc)
40
41	sec := secret()
42
43	s := NewSecretStoreRevokableSecretService()
44	err := s.StoreSecret(mctx, alice, sec)
45	require.NoError(t, err)
46
47	gotSec, err := s.RetrieveSecret(mctx, alice)
48	require.NoError(t, err)
49	require.Equal(t, sec, gotSec)
50
51	err = s.ClearSecret(mctx, alice)
52	require.NoError(t, err)
53
54	_, err = s.RetrieveSecret(mctx, alice)
55	requireError(t, err.(UnboxError), "no such file")
56
57	err = s.StoreSecret(mctx, alice, sec)
58	require.NoError(t, err)
59	err = s.StoreSecret(mctx, bob, sec)
60	require.NoError(t, err)
61	err = s.StoreSecret(mctx, charlie, sec)
62	require.NoError(t, err)
63	gotSec, err = s.RetrieveSecret(mctx, charlie)
64	require.NoError(t, err)
65	require.Equal(t, sec, gotSec)
66
67	users, err := s.GetUsersWithStoredSecrets(mctx)
68	require.NoError(t, err)
69	require.Equal(t, []string{"alice", "bob", "charlie"}, users)
70
71	err = s.ClearSecret(mctx, alice)
72	require.NoError(t, err)
73	err = s.ClearSecret(mctx, bob)
74	require.NoError(t, err)
75	err = s.ClearSecret(mctx, charlie)
76	require.NoError(t, err)
77}
78
79func TestSSSSCorruptKeystore(t *testing.T) {
80	t.Skip("Skipping secret service test while Linux CI AMI is being upgraded to include keyring")
81
82	tc := SetupTest(t, "secret_store_secretservice", 0)
83	defer tc.Cleanup()
84	mctx := NewMetaContextForTest(tc)
85
86	s := NewSecretStoreRevokableSecretService()
87	err := s.StoreSecret(mctx, alice, secret())
88	require.NoError(t, err)
89
90	keystore := s.keystore(mctx, "alice", nil)
91	keypath := keystore.(*FileErasableKVStore).filepath(s.keystoreKey())
92	file, err := os.OpenFile(keypath, os.O_RDWR, 0755)
93	defer func() {
94		err := file.Close()
95		require.NoError(t, err)
96	}()
97	require.NoError(t, err)
98	_, err = file.Write([]byte("YELLOW_SUBMARINE"))
99	require.NoError(t, err)
100
101	_, err = s.RetrieveSecret(mctx, alice)
102	require.Error(t, err)
103	requireError(t, err.(UnboxError), "msgpack decode error")
104
105	err = s.ClearSecret(mctx, alice)
106	require.NoError(t, err)
107}
108
109func TestSSSSCorruptNoise(t *testing.T) {
110	t.Skip("Skipping secret service test while Linux CI AMI is being upgraded to include keyring")
111
112	tc := SetupTest(t, "secret_store_secretservice", 0)
113	defer tc.Cleanup()
114	mctx := NewMetaContextForTest(tc)
115
116	s := NewSecretStoreRevokableSecretService()
117	err := s.StoreSecret(mctx, alice, secret())
118	require.NoError(t, err)
119
120	keystore := s.keystore(mctx, "alice", nil)
121	fileKeystore := keystore.(*FileErasableKVStore)
122	keypath := fileKeystore.filepath(fileKeystore.noiseKey(s.keystoreKey()))
123	file, err := os.OpenFile(keypath, os.O_RDWR, 0755)
124	defer func() {
125		err := file.Close()
126		require.NoError(t, err)
127	}()
128	require.NoError(t, err)
129	_, err = file.Write([]byte("YELLOW_SUBMARINE"))
130	require.NoError(t, err)
131
132	_, err = s.RetrieveSecret(mctx, alice)
133	require.Error(t, err)
134	require.Equal(t, err.(UnboxError).Info(), "noise hashes do not match")
135
136	err = s.ClearSecret(mctx, alice)
137	require.NoError(t, err)
138}
139
140func TestSSSSCorruptKeyring(t *testing.T) {
141	t.Skip("Skipping secret service test while Linux CI AMI is being upgraded to include keyring")
142
143	tc := SetupTest(t, "secret_store_secretservice", 0)
144	defer tc.Cleanup()
145	mctx := NewMetaContextForTest(tc)
146
147	s := NewSecretStoreRevokableSecretService()
148
149	err := s.StoreSecret(mctx, alice, secret())
150	require.NoError(t, err)
151
152	srv, err := secsrv.NewService()
153	require.NoError(t, err)
154	session, err := srv.OpenSession(secsrv.AuthenticationDHAES)
155	require.NoError(t, err)
156	defer srv.CloseSession(session)
157	identifierKeystore := s.identifierKeystore(mctx)
158	var instanceIdentifier []byte
159	err = identifierKeystore.Get(mctx, s.identifierKeystoreKey("alice"), &instanceIdentifier)
160	require.NoError(t, err)
161	label := fmt.Sprintf("%s@%s", "alice", mctx.G().Env.GetStoredSecretServiceName())
162	properties := secsrv.NewSecretProperties(label, s.makeAttributes(mctx, "alice", instanceIdentifier))
163	srvSecret, err := session.NewSecret([]byte("NOT_THE_REAL_SECRET"))
164	require.NoError(t, err)
165	_, err = srv.CreateItem(secsrv.DefaultCollection, properties, srvSecret, secsrv.ReplaceBehaviorReplace)
166	require.NoError(t, err)
167
168	_, err = s.RetrieveSecret(mctx, alice)
169	require.Error(t, err)
170	require.Equal(t, err.(UnboxError).Info(), "noise hashes match")
171	// (i.e., issue is something else - likely a MAC mismatch, but secretbox.Open doesn't give a more specific error)
172
173	err = s.ClearSecret(mctx, alice)
174	require.NoError(t, err)
175}
176