1// Copyright 2015 Keybase, Inc. All rights reserved. Use of
2// this source code is governed by the included BSD license.
3
4package engine
5
6import (
7	"runtime/debug"
8	"strings"
9	"testing"
10
11	"github.com/keybase/client/go/libkb"
12	"github.com/stretchr/testify/require"
13)
14
15func TestGenerateNewPGPKey(t *testing.T) {
16	tc := SetupEngineTest(t, "pgp")
17	defer tc.Cleanup()
18	fu := CreateAndSignupFakeUser(tc, "pgp")
19	secui := &libkb.TestSecretUI{Passphrase: fu.Passphrase}
20	arg := PGPKeyImportEngineArg{
21		Gen: &libkb.PGPGenArg{
22			PrimaryBits: 768,
23			SubkeyBits:  768,
24		},
25	}
26	err := arg.Gen.MakeAllIds(tc.G)
27	require.NoError(t, err)
28	uis := libkb.UIs{
29		LogUI:    tc.G.UI.GetLogUI(),
30		SecretUI: secui,
31	}
32	eng := NewPGPKeyImportEngine(tc.G, arg)
33	m := NewMetaContextForTest(tc).WithUIs(uis)
34	err = RunEngine2(m, eng)
35	if err != nil {
36		t.Fatal(err)
37	}
38}
39
40func TestPGPUserInterface(t *testing.T) {
41	p := newPgpPair(t)
42	defer p.cleanup()
43
44	p.assert(!p.senderTracksRecipient(), "sender shouldn't track recipient")
45	p.assert(!p.recipientTracksSender(), "recipient shouldn't track sender")
46
47	// encrypt, not signed
48	notSigned, idCount := p.encrypt(false)
49
50	// test that identify ui was shown once to sender for recipient
51	p.assertEqual(idCount, 1, "identify ui count [encrypt, not signed]")
52	// with identify2, no tracking, so test that sender doesn't track recipient
53	p.assert(!p.senderTracksRecipient(), "after encrypt, sender shouldn't track recipient")
54	p.assert(!p.recipientTracksSender(), "after encrypt, recipient shouldn't track sender")
55
56	// encrypt, signed
57	signed, idCount := p.encrypt(true)
58
59	// test that identify ui was *not* shown to sender for recipient since
60	// just shown in previous p.encrypt() call.
61	p.assertEqual(idCount, 0, "identify ui count [encrypt, signed]")
62	// with identify2, not tracking, so test that sender doesn't track recipient
63	p.assert(!p.senderTracksRecipient(), "after encrypt, sender shouldn't track recipient")
64	p.assert(!p.recipientTracksSender(), "after encrypt, recipient shouldn't track sender")
65
66	// decrypt, not signed
67	p.checkIdentifyUIAndPgpUI("decrypt not signed", p.decrypt, notSigned, 0)
68
69	// decrypt signed
70	p.checkIdentifyUIAndPgpUI("decrypt signed", p.decrypt, signed, 1)
71
72	// decrypt signed, assert signed by anyone
73	p.checkIdentifyUIAndPgpUI("decrypt assert signed", p.decryptAssertSigned, signed, 1)
74
75	// decrypt signed with user assertion
76	p.checkIdentifyUIAndPgpUI("decrypt assert signed by", p.decryptAssertSignedBySender, signed, 1)
77
78	// decrypt signed by self
79	p.checkIdentifyUIAndPgpUI("decrypt self", p.decryptSelf, signed, 1)
80
81	// decrypt assert signed by self
82	p.checkIdentifyUIAndPgpUI("decrypt assert signed by self", p.decryptAssertSignedBySelf, signed, 1)
83
84	// verify signed
85	p.checkIdentifyUIAndPgpUI("verify signed", p.verify, signed, 1)
86
87	// verify signed with assertion
88	p.checkIdentifyUIAndPgpUI("verify assert signed by", p.verifyAssertSignedBySender, signed, 1)
89
90	// verify signed by self
91	p.checkIdentifyUIAndPgpUI("verify self", p.verifySelf, signed, 1)
92
93	// verify assert signed by self
94	p.checkIdentifyUIAndPgpUI("verify assert signed by self", p.verifyAssertSignedBySelf, signed, 1)
95}
96
97type pgpPair struct {
98	t         *testing.T
99	tcS       libkb.TestContext
100	tcR       libkb.TestContext
101	sender    *FakeUser
102	recipient *FakeUser
103}
104
105func newPgpPair(t *testing.T) *pgpPair {
106	p := pgpPair{t: t}
107	p.tcS = SetupEngineTest(t, "sender")
108	p.sender = createFakeUserWithPGPSibkey(p.tcS)
109
110	p.tcR = SetupEngineTest(t, "recip")
111	p.recipient = createFakeUserWithPGPSibkey(p.tcR)
112	return &p
113}
114
115func (p *pgpPair) cleanup() {
116	p.tcS.Cleanup()
117	p.tcR.Cleanup()
118}
119
120func (p *pgpPair) assert(b bool, m string) {
121	if b {
122		return
123	}
124	p.t.Fatal(m)
125}
126
127func (p *pgpPair) assertEqual(actual, expected int, m string) {
128	if actual == expected {
129		return
130	}
131	p.t.Fatalf("%s: %d, expected %d", m, actual, expected)
132}
133
134func (p *pgpPair) checkIdentifyUIAndPgpUI(name string, f func(string) (int, int), m string, n int) {
135	idCount, sigCount := f(m)
136
137	// test that identify ui was shown n times
138	p.assertEqual(idCount, n, name+": identify ui count")
139	// test that recipient does not track sender
140	p.assert(!p.recipientTracksSender(), name+": recipient shouldn't track sender")
141	// test that signature success was shown n times
142	p.assertEqual(sigCount, n, name+": sig ui count")
143}
144
145func (p *pgpPair) senderTracksRecipient() bool {
146	return p.isTracking(p.tcS, p.recipient.Username)
147}
148
149func (p *pgpPair) recipientTracksSender() bool {
150	return p.isTracking(p.tcR, p.sender.Username)
151}
152
153func (p *pgpPair) isTracking(meContext libkb.TestContext, username string) bool {
154	me, err := libkb.LoadMe(libkb.NewLoadUserArg(meContext.G))
155	if err != nil {
156		p.t.Fatal(err)
157	}
158	them, err := libkb.LoadUser(libkb.NewLoadUserByNameArg(meContext.G, username))
159	if err != nil {
160		p.t.Fatal(err)
161	}
162	m := NewMetaContextForTest(meContext)
163	s, err := me.TrackChainLinkFor(m, them.GetNormalizedName(), them.GetUID())
164	if err != nil {
165		p.t.Fatal(err)
166	}
167	return s != nil
168}
169
170func (p *pgpPair) encrypt(sign bool) (string, int) {
171	uis := libkb.UIs{
172		IdentifyUI: &FakeIdentifyUI{},
173		PgpUI:      &TestPgpUI{},
174		SecretUI:   p.sender.NewSecretUI(),
175	}
176	sink := libkb.NewBufferCloser()
177	arg := &PGPEncryptArg{
178		Recips: []string{p.recipient.Username},
179		Source: strings.NewReader("thank you for your order"),
180		Sink:   sink,
181		NoSign: !sign,
182	}
183
184	eng := NewPGPEncrypt(p.tcS.G, arg)
185	m := NewMetaContextForTest(p.tcS).WithUIs(uis)
186	if err := RunEngine2(m, eng); err != nil {
187		p.t.Fatal(err)
188	}
189
190	out := sink.Bytes()
191
192	return string(out), p.idc(m)
193}
194
195func (p *pgpPair) decrypt(msg string) (int, int) {
196	return p.doDecrypt(msg, &PGPDecryptArg{})
197}
198
199func (p *pgpPair) decryptAssertSigned(msg string) (int, int) {
200	return p.doDecrypt(msg, &PGPDecryptArg{AssertSigned: true})
201}
202
203func (p *pgpPair) decryptAssertSignedBySender(msg string) (int, int) {
204	return p.doDecrypt(msg, &PGPDecryptArg{SignedBy: p.sender.Username})
205}
206
207func (p *pgpPair) decryptSelf(msg string) (int, int) {
208	ctx := decengctx(p.sender, p.tcS)
209	arg := &PGPDecryptArg{
210		Source: strings.NewReader(msg),
211		Sink:   libkb.NewBufferCloser(),
212	}
213	dec := NewPGPDecrypt(p.tcS.G, arg)
214	if err := RunEngine2(ctx, dec); err != nil {
215		p.t.Fatal(err)
216	}
217	return p.idc(ctx), p.sigc(ctx)
218}
219
220func (p *pgpPair) decryptAssertSignedBySelf(msg string) (int, int) {
221	ctx := decengctx(p.sender, p.tcS)
222	arg := &PGPDecryptArg{
223		Source:   strings.NewReader(msg),
224		Sink:     libkb.NewBufferCloser(),
225		SignedBy: p.sender.Username,
226	}
227	dec := NewPGPDecrypt(p.tcS.G, arg)
228	if err := RunEngine2(ctx, dec); err != nil {
229		p.t.Fatal(err)
230	}
231	return p.idc(ctx), p.sigc(ctx)
232}
233
234func (p *pgpPair) doDecrypt(msg string, arg *PGPDecryptArg) (int, int) {
235	ctx := decengctx(p.recipient, p.tcR)
236	arg.Source = strings.NewReader(msg)
237	arg.Sink = libkb.NewBufferCloser()
238	dec := NewPGPDecrypt(p.tcR.G, arg)
239	if err := RunEngine2(ctx, dec); err != nil {
240		debug.PrintStack()
241		p.t.Fatal(err)
242	}
243	return p.idc(ctx), p.sigc(ctx)
244}
245
246func (p *pgpPair) verify(msg string) (int, int) {
247	ctx := decengctx(p.recipient, p.tcR)
248	arg := &PGPVerifyArg{
249		Source: strings.NewReader(msg),
250	}
251	eng := NewPGPVerify(p.tcR.G, arg)
252	if err := RunEngine2(ctx, eng); err != nil {
253		p.t.Fatal(err)
254	}
255	return p.idc(ctx), p.sigc(ctx)
256}
257
258func (p *pgpPair) verifyAssertSignedBySender(msg string) (int, int) {
259	ctx := decengctx(p.recipient, p.tcR)
260	arg := &PGPVerifyArg{
261		Source:   strings.NewReader(msg),
262		SignedBy: p.sender.Username,
263	}
264	eng := NewPGPVerify(p.tcR.G, arg)
265	if err := RunEngine2(ctx, eng); err != nil {
266		p.t.Fatal(err)
267	}
268	return p.idc(ctx), p.sigc(ctx)
269}
270
271func (p *pgpPair) verifySelf(msg string) (int, int) {
272	ctx := decengctx(p.sender, p.tcS)
273	arg := &PGPVerifyArg{
274		Source: strings.NewReader(msg),
275	}
276	eng := NewPGPVerify(p.tcS.G, arg)
277	if err := RunEngine2(ctx, eng); err != nil {
278		p.t.Fatal(err)
279	}
280	return p.idc(ctx), p.sigc(ctx)
281}
282
283func (p *pgpPair) verifyAssertSignedBySelf(msg string) (int, int) {
284	ctx := decengctx(p.sender, p.tcS)
285	arg := &PGPVerifyArg{
286		Source:   strings.NewReader(msg),
287		SignedBy: p.sender.Username,
288	}
289	eng := NewPGPVerify(p.tcS.G, arg)
290	if err := RunEngine2(ctx, eng); err != nil {
291		p.t.Fatal(err)
292	}
293	return p.idc(ctx), p.sigc(ctx)
294}
295
296func (p *pgpPair) idc(m libkb.MetaContext) int {
297	ui, ok := m.UIs().IdentifyUI.(*FakeIdentifyUI)
298	if !ok {
299		p.t.Fatalf("not FakeIdentifyUI: %T", m.UIs().IdentifyUI)
300	}
301	p.t.Logf("FakeIdentifyUI: %+v", ui)
302	return ui.StartCount
303}
304
305func (p *pgpPair) sigc(m libkb.MetaContext) int {
306	ui, ok := m.UIs().PgpUI.(*TestPgpUI)
307	if !ok {
308		p.t.Fatalf("not TestPgpUI: %T", m.UIs().PgpUI)
309	}
310	return ui.OutputCount
311}
312