1// Copyright 2015 Keybase, Inc. All rights reserved. Use of
2// this source code is governed by the included BSD license.
3
4package libkb
5
6import (
7	"bytes"
8	"strings"
9	"testing"
10)
11
12func parse(t *testing.T, kr string) *GpgKeyIndex {
13	tc := SetupTest(t, "parse", 2)
14	defer tc.Cleanup()
15	buf := bytes.NewBufferString(kr)
16	i, w, e := ParseGpgIndexStream(tc.MetaContext(), buf)
17	if e != nil {
18		t.Fatalf("failure in parse: %s", e)
19	}
20
21	if !w.IsEmpty() {
22		t.Errorf("Warnings in parsing:")
23		for _, e := range w.Warnings() {
24			t.Errorf(" - %s", e)
25		}
26		return nil
27	}
28	return i
29}
30
31func TestParseMyKeyring(t *testing.T) {
32	parse(t, myKeyring)
33}
34
35func TestFindMax(t *testing.T) {
36	index := parse(t, myKeyring)
37	keylist := index.Emails.Get("themax@gmail.com")
38	if keylist == nil {
39		t.Errorf("nil keylist was not expected")
40	} else if len(keylist) != 2 {
41		t.Errorf("expected two keys for max")
42	} else {
43		expected := map[string]bool{
44			"8EFBE2E4DD56B35273634E8F6052B2AD31A6631C": true,
45			"4475293306243408FA5958DC63847B4B83930F0C": true,
46		}
47		for _, k := range keylist {
48			if fp := k.GetFingerprint(); fp == nil {
49				t.Errorf("Unexpected empty fingerprint")
50			} else if ok, found := expected[strings.ToUpper(fp.String())]; !ok || !found {
51				t.Errorf("Unexpected fingerprint: %s", fp.String())
52			}
53		}
54	}
55}
56
57func TestYubikeyFixedSecretKeys(t *testing.T) {
58	index := parse(t, yubikey4fixed)
59	keylist := index.Emails.Get("dain@yubico.com")
60	if keylist == nil {
61		t.Errorf("nil keylist was not expected")
62	} else if len(keylist) != 1 {
63		t.Errorf("expected two keys for max")
64	}
65}
66
67func TestYubikeyOrigSecretKeys(t *testing.T) {
68	index := parse(t, yubikey4orig)
69	keylist := index.Emails.Get("dain@yubico.com")
70	if keylist != nil {
71		t.Errorf("nil keylist was expected")
72	}
73}
74
75func TestGPGIndex2Dot1(t *testing.T) {
76	index := parse(t, gpg2dot1)
77	if index == nil {
78		t.Fatal("parsing failed")
79	}
80	keylist := index.Emails.Get("themax+test@gmail.com")
81	if keylist == nil {
82		t.Errorf("nil keylist was not expected")
83	} else if len(keylist) != 1 {
84		t.Errorf("expected one key for max")
85	}
86}
87
88func TestGPGFindGreg(t *testing.T) {
89	index := parse(t, greg)
90	if index == nil {
91		t.Fatal("parsing failed")
92	}
93	keys := index.Fingerprints.Get("6A457A06CB07E916EC88EC741193ACD196ED61F2")
94	if len(keys) == 0 {
95		t.Fatal("expected to find greg's key")
96	}
97}
98
99func TestGPGRevokedID(t *testing.T) {
100	index := parse(t, keyringRevokedID)
101	if index == nil {
102		t.Fatal("parsing failed")
103	}
104	keys := index.Fingerprints.Get("582AB5DE7B6BB11F6E2B7075851B3498422B2DFA")
105	if len(keys) != 1 {
106		t.Fatal("expected to find one key")
107	}
108	if numIds := len(keys[0].identities); numIds != 1 {
109		t.Fatalf("expected to have one identity (got %v)", numIds)
110	}
111	if keys[0].identities[0].Format() != "This One WIll be rev0ked" {
112		t.Fatalf("Invalid identity: %v", keys[0].identities[0])
113	}
114}
115
116const myKeyring = `
117tru::1:1416474053:1439900531:3:1:5
118pub:u:2048:17:76D78F0500D026C4:1282220531:1439900531::u:::scESC:
119fpr:::::::::85E38F69046B44C1EC9FB07B76D78F0500D026C4:
120uid:u::::1344775710::CAACC8CE9116A0BE42E58C61602F127B194EF5A5::GPGTools Team <team@gpgtools.org>:
121uid:u::::1282220531::03B2DCE7652DBBB93DA77FFC4328F122656E20DD::GPGMail Project Team (Official OpenPGP Key) <gpgmail-devel@lists.gpgmail.org>:
122uid:u::::1344775710::8CACAFAD028BE38151D2361F9CD79CC81B4153B2::GPGTools Project Team (Official OpenPGP Key) <gpgtools-org@lists.gpgtools.org>:
123uat:u::::1321476238::076E59FC200B10E38AEEA745AB6547AEE99FB9EE::1 5890:
124sub:u:2048:16:07EAE49ADBCBE671:1282220531:1439900531:::::e:
125fpr:::::::::CF5DA29DD13D6856B5820B2F07EAE49ADBCBE671:
126sub:u:4096:1:E8A664480D9E43F5:1396950003:1704188403:::::s:
127fpr:::::::::8C31E5A17DD5D932B448FE1DE8A664480D9E43F5:
128pub:u:4096:1:FBC07D6A97016CB3:1381159886:1507390286::u:::escaESCA:
129fpr:::::::::94AA3A5BDBD40EA549CABAF9FBC07D6A97016CB3:
130uid:u::::1415222273::323D79D8863BA8F45C43217AA3197816DB1D6C82::Chris Coyne <chris@okcupid.com>:
131uid:u::::1381159886::CF5361B3D400B377CED49FD557B744E93FA344D4::Chris Coyne <chris@chriscoyne.com>:
132uid:u::::1415222233::4690BE55B82498795187834A5B960515BAE36113::Chris Coyne <ccoyne77@gmail.com>:
133uid:u::::1381159886::9DFEAB6033B858FD7A80C11E5E31EA709573D7E9::keybase.io/chris <chris@keybase.io>:
134sub:u:4096:1:D224413B1CFA6490:1381159886:1507390286:::::esa:
135fpr:::::::::803634EFEB38F9370F9C58ABD224413B1CFA6490:
136pub:-:4096:1:4F04069FE2052317:1392417704:1707777704::-:::escaESCA:
137fpr:::::::::419877544E88410632624ACB4F04069FE2052317:
138uid:-::::1392417704::D2D2A2969DF6DC0B947CE9D17CC356EBE3822937::keybase.io/aston <aston@keybase.io>:
139sub:-:4096:1:C502FF1549ABE8E7:1392417704:1707777704:::::esa:
140fpr:::::::::12D125686EE1310D8C3219F9C502FF1549ABE8E7:
141pub:u:4096:1:47484E50656D16C7:1384876967:1511107367::u:::scESC:
142fpr:::::::::222B85B0F90BE2D24CFEB93F47484E50656D16C7:
143uid:u::::1384876967::5379B9706C5D468C86A572B07E28EBDB26BE0E97::Keybase.io Code Signing (v1) <code@keybase.io>:
144sub:u:4096:1:5929664098F03378:1384876967:1511107367:::::e:
145fpr:::::::::10F79F9BEB724B73FB673D385929664098F03378:
146pub:u:4096:1:63847B4B83930F0C:1380929487:1607159887::u:::escaESCA:
147fpr:::::::::4475293306243408FA5958DC63847B4B83930F0C:
148uid:u::::1387217771::759D5C7C38AD60551D46D2E6F34BA03640FE4379::Maxwell Krohn <themax@gmail.com>:
149uid:u::::1380929487::14BC0C35326061518657E0B8F71A23E0CA537034::Max Krohn <themax@gmail.com>:
150sub:u:4096:1:2FE01C454348DA39:1380929487:1607159887:::::esa:
151fpr:::::::::C4EE7BCBCE2F0953DCF9E8902FE01C454348DA39:
152pub:u:2048:1:2EE0695E30C55BEF:1392816673:1708176673::u:::scESC:
153fpr:::::::::F1DEFAA6B3DB297FB824CB512EE0695E30C55BEF:
154uid:u::::1392816673::082E8013E42FE9646212330D7931B969029485CE::Max Test (test) <themax+1@gmail.com>:
155sub:u:2048:1:091E2177A50BA645:1392816673:1708176673:::::e:
156fpr:::::::::B80B0A78852880A93FE421BD091E2177A50BA645:
157pub:-:4096:1:EBF01804BCF05F6B:1346326188:::-:::escaESCA:
158fpr:::::::::428DF5D63EF07494BB455AC0EBF01804BCF05F6B:
159uid:-::::1388587863::2D64E83198C753709219CA0FDF17A2A48D994366::Filippo Valsorda <fv@filippo.io>:
160uid:-::::1388587850::ED4AFBC98FD3B49AE8CA7733A27BE82FFFB5E53F::Filippo Valsorda <filippo.valsorda@gmail.com>:
161uid:-::::1360528876::788372CBC7DDF24564AEA7138ABB09A648499E32::Filippo Valsorda <filosottile.wiki@gmail.com>:
162sub:e:2048:1:50223425F149AA25:1360529005:1392065005:::::s:
163fpr:::::::::2D098FADCE5B408F1C77F8E750223425F149AA25:
164sub:e:2048:1:3D1C752C0D83D9EC:1360529191:1392065191:::::e:
165fpr:::::::::40D449F18A85797C8E1770B43D1C752C0D83D9EC:
166sub:-:2048:1:204D8240101F5216:1388587898:1420123898:::::s:
167fpr:::::::::ED2914BDFDDBB162C77A9F80204D8240101F5216:
168sub:-:2048:1:262B4EF067BA72AF:1388588025:1420124025:::::e:
169fpr:::::::::72F48FF302283C9FA3CFD5B5262B4EF067BA72AF:
170pub:u:1024:17:910A9D8D1792F55B:1392902586:1708262586::u:::scESC:
171fpr:::::::::37D30E298D0045FDDD506346910A9D8D1792F55B:
172uid:u::::1392902586::AD6E6A9DA7A2A867CA8867393464E0D439ECFDDE::Max Planck (password is 'mmpp') <planck@berlin.ac.de>:
173uid:u::::1392902586::14EBD18210821757B348F0974CE9AC8AEAFF97BA::keybase.io/max2 <max2@keybase.io>:
174sub:u:1024:16:A1910E8DC491E958:1392902586:1708262586:::::e:
175fpr:::::::::0C0A78ECB880319EBE801C87A1910E8DC491E958:
176pub:u:2048:1:D2CBE4585360C01C:1392926252:1708286252::u:::scESC:
177fpr:::::::::1DBC14CFDCA08845CEF8D56ED2CBE4585360C01C:
178uid:u::::1392926252::56C755C67184046B404B3343B144A4D7B642A894::Herb Kitch (Test Key) <herb.ketch@gov.uk>:
179sub:u:2048:1:2C95AFC9FDC426E5:1392926252:1708286252:::::e:
180fpr:::::::::D604AFB62A06807B7FB124B52C95AFC9FDC426E5:
181pub:u:4096:1:919305DF414C79F6:1393194839:1708554839::u:::scESC:
182fpr:::::::::D53D874FEB31616F51D81069919305DF414C79F6:
183uid:u::::1393194839::1D5AA43907416362F096D2D34AEE8F1805576124::Keybase Backup (v1) <backup@keybase.io>:
184sub:u:4096:1:250D3F1E2F22B529:1393194839:1708554839:::::e:
185fpr:::::::::6C397E3C502192933DD0C144250D3F1E2F22B529:
186pub:u:4096:1:E26A29910D2470BE:1392486098:1707846098::u:::escaESCA:
187fpr:::::::::C136F24BFB6CCA288158B576E26A29910D2470BE:
188uid:u::::1392486098::C973E2B56D13F1CF8C4A57076C046672ADFDE145::keybase.io/wdaher (v0.0.1) <wdaher@keybase.io>:
189sub:u:2048:1:F703B25389906F33:1392486098:1424022098:::::esa:
190fpr:::::::::4580569CD7D98B4643404568F703B25389906F33:
191pub:-:8192:1:0DAA1A4AB1D88291:1392437545:1613189545::-:::scESC:
192fpr:::::::::5E685E60EB8733654DCB00570DAA1A4AB1D88291:
193uid:-::::1392438504::A6B93F697800D36A086BC778081AC77B239BB065::Sidney San Martín (Born 1989-7-1 in San Francisco, CA):
194uid:-::::1392438141::988DE166E3890A7DDDACCFD2D5350A7149E5078B::Sidney San Martín <sidney@okcupid.com>:
195uid:-::::1392438106::3F8A606B1389583AB0FE77059ACA0251BBBB5B3B::Sidney San Martín <sidney@s4y.us>:
196sub:-:8192:1:2831A2BE59FEA86F:1392437545:1613189545:::::e:
197fpr:::::::::3DD85340C60CB3173AB8579B2831A2BE59FEA86F:
198pub:-:4096:1:288EDB4733616035:1390306245:1705666245::-:::scESC:
199fpr:::::::::B658B173C61EA483C0D01E9D288EDB4733616035:
200uid:-::::1391052728::E5E8323D8182BB40FDB129D625AF30DC6F2B62C4::Andrew Gwozdziewycz <apg@sigusr2.net>:
201uid:-::::1390306245::8A39C264E3F6DE6A226406D92FA23C6ABF5BE20C::Andrew Gwozdziewycz <me@apgwoz.com>:
202uid:-::::1391052536::C8A26F3904DC08993B6F4D116CAE27C06917E539::Andrew Gwozdziewycz <web@apgwoz.com>:
203uid:-::::1391052673::1D0B55B327BE733076BCACD1454B80DA9146AD85::Andrew Gwozdziewycz <git@apgwoz.com>:
204uid:-::::1391052696::730D53519F1910B97CA9E867B7DD8F3EEF64A1FD::Andrew Gwozdziewycz <apgwoz@gmail.com>:
205sub:-:4096:1:989275C75347F303:1390306245:1705666245:::::e:
206fpr:::::::::AFA3F945A6D05343AD283F32989275C75347F303:
207pub:-:4096:1:D28390C6F7CDD0BA:1393259803:1708619803::-:::escaESCA:
208fpr:::::::::F544F89FB9AFC481DCB26730D28390C6F7CDD0BA:
209uid:-::::1393259803::2249EEC3751364F2E3BB0CAFD34A6C9785A9AD26::keybase.io/max1 <max1@keybase.io>:
210sub:-:4096:1:FE968337A60DA0A4:1393259803:1708619803:::::esa:
211fpr:::::::::A9929FBBE9AE7EF674346449FE968337A60DA0A4:
212pub:-:1024:17:AC859362B0413BFA:943674453:::-:::scESC:
213fpr:::::::::DE47BC9E6D2DA6B02DC610B1AC859362B0413BFA:
214uid:-::::1377018882::38128A333FFB8FA1D4387F9F3C65A2D2FEE2D1C1::Gregory Maxwell <greg@xiph.org>:
215uid:-::::1377018880::5415DACFD5BBC93B9C86389B3521A7E15C9CC7DE::Gregory Maxwell <gmaxwell@gmail.com>:
216uid:r::::::91723BCF5FAF8940D24572242529D7F9F74CC688::Gregory Maxwell <gmaxwell@juniper.net>:
217uid:r::::::A4248851EFC00E1A833E10262FC7F8250F314CCD::Gregory Maxwell <greg@linuxpower.cx>:
218uid:r::::::C387E59FC7500938AC6CCAEB03A87F107CCAEB57::Gregory Maxwell <gmaxwell@martin.fl.us>:
219uat:-::::1142671127::C020317D61C27D09BC7409382714F5EA4B0B9A7F::1 6038:
220uid:-::::1174738550::3F9A302C8FB31B0D49E87503D6353EAB1E9454C8::Gregory Maxwell <gmaxwell@wikimedia.org>:
221uid:-::::1360375343::DCD6D818D89EFBD7FA7D1004EE9954FAB6EE14EC::Gregory Maxwell <gmaxwell@mozilla.com>:
222sub:r:2048:16:3261CC7DF0F0B355:943674503::::::e:
223fpr:::::::::CCE142FB2426C09B41A60C8C3261CC7DF0F0B355:
224sub:-:4096:1:C2A8CB2A253F3FDF:1377018918:1503162918:::::e:
225fpr:::::::::20595CB8560782DF302CC318C2A8CB2A253F3FDF:
226sub:-:4096:1:EAB5AF94D9E9ABE7:1377634098:1535314098:::::s:
227fpr:::::::::81291FA67D2C379A006A053FEAB5AF94D9E9ABE7:
228pub:u:4096:1:6052B2AD31A6631C:1391639420:1706999420::u:::escaESCA:
229fpr:::::::::8EFBE2E4DD56B35273634E8F6052B2AD31A6631C:
230uid:u::::1414603912::759D5C7C38AD60551D46D2E6F34BA03640FE4379::Maxwell Krohn <themax@gmail.com>:
231uid:u::::1414603912::0E83836893BE1130CC0CCF718A26FA19BCDC5866::keybase.io/max (v0.0.1) <max@keybase.io>:
232uid:u::::1394818042::53811772132DAA1EC145F05E27F6298AAA521587::Maxwell Krohn <max@maxk.org>:
233uid:u::::1395683671::4994E49FCED0284AF063655ADFDBCB12B4F65745::Maxwell Krohn <krohn@mit.edu>:
234uid:u::::1395683700::1AACE33F196DC383CA09DF1485F5086412693E63::Maxwell Krohn <krohn@post.harvard.edu>:
235uid:u::::1395683771::EEDD36E49A9440C83645A385F4F9D9FFA3A051D9::Maxwell Krohn <krohn@alum.mit.edu>:
236sub:u:2048:1:980A3F0D01FE04DF:1391639420:1423175420:::::esa:
237fpr:::::::::4AF88842F72A59565C669BDE980A3F0D01FE04DF:
238pub:-:4096:1:EF64151CD1B1B13E:1393625258:1708985258::-:::escaESCA:
239fpr:::::::::3F00CA464E081B2204AE7842EF64151CD1B1B13E:
240uid:-::::1393625258::3541B4CE1F8EDDAB0A4C04A0C91F01847E183140::keybase.io/paritybit (v0.0.1) <paritybit@keybase.io>:
241sub:-:2048:1:2A0688A6E2DC575B:1393625258:1425161258:::::esa:
242fpr:::::::::E1D8C791E3A2B91C436051272A0688A6E2DC575B:
243sec::4096:1:3D2EEBE27EF8DEC6:1469640924:1595871324:::::scESC::::
244fpr:::::::::41AC4E75A5F6859DA6889B483D2EEBE27EF8DEC6:
245uid:::::1469640924::364F26DE007A0238E53F7CB330F2CA64AF70047E::"Barb Akew (x)" <test@test.com>:
246ssb::4096:1:3F71D92DD46BC4BC:1469640924:1595871324:::::e::::
247`
248
249// Dain sent us this Yubikey keyring with an expired primary
250const yubikey4orig = `sec::2048:1:F04367096FBA95E8:1389358404:1444907030::::::::D2760001240102010006042129000000:
251fpr:::::::::20EE325B86A81BCBD3E56798F04367096FBA95E8:
252uid:::::::CBDD6BD90F5A01A814C4E5A0E05F8D7DC7B3D070::Dain Nilsson <dain@yubico.com>:
253ssb::2048:1:BFE3A8E58DB04E9F:1389358404:::::::::D2760001240102010006042129000000:
254ssb::2048:1:3B557A2E4C844B75:1389358510:::::::::D2760001240102010006042129000000:
255`
256
257// We then fixed it by undoing the expiration time.
258const yubikey4fixed = `sec::2048:1:F04367096FBA95E8:1389358404:0::::::::D2760001240102010006042129000000:
259fpr:::::::::20EE325B86A81BCBD3E56798F04367096FBA95E8:
260uid:::::::CBDD6BD90F5A01A814C4E5A0E05F8D7DC7B3D070::Dain Nilsson <dain@yubico.com>:
261ssb::2048:1:BFE3A8E58DB04E9F:1389358404:::::::::D2760001240102010006042129000000:
262ssb::2048:1:3B557A2E4C844B75:1389358510:::::::::D2760001240102010006042129000000:
263`
264
265// GPG 2.1.15ish broke everything...
266const gpg2dot1 = `
267sec:u:256:22:586422EFB7394E3D:1439134482:::u:::scSC:::+::ed25519::
268fpr:::::::::CC79CFE4C04CA6A75A69D20C586422EFB7394E3D:
269grp:::::::::57A65E8BF2417FF87D122A62385AF262B73EA6FC:
270uid:u::::1439134482::2667AF1B2E54C3582718E837343DC8F09B81E3F5::Early Adopter (PW is abcd) <early@adopt.er>:::::::::
271sec:u:256:22:7B2E3F571BF26EB7:1475200495:::u:::scESC:::+::ed25519::
272fpr:::::::::C0045FBD76822E6BBB78C7707B2E3F571BF26EB7:
273grp:::::::::3D436BF15A556C1D9BF5D420AB5C44A4008C4894:
274uid:u::::1475200495::92725E39A37C33E515983C6B0D25E7320ABB8247::Max Test <themax+test@gmail.com>:::::::::
275ssb:u:256:18:A0E78D11A79FE1EF:1475200495::::::e:::+::cv25519:
276fpr:::::::::39DC5F5D9252DDA6F5BF660CA0E78D11A79FE1EF:
277grp:::::::::7872FB84783726E5B066CEF45D6DEC2F2364A2A5:
278`
279const greg = `
280sec:u:1024:17:1193ACD196ED61F2:1149381441:::u:::scESC:::+::::
281fpr:::::::::6A457A06CB07E916EC88EC741193ACD196ED61F2:
282grp:::::::::FD72593CF57F00142A7514558A4CA8FFBE36F076:
283uid:u::::1245342200::90A49BDC6914351F4F2BDF295723DE5323BE42E1::Gregory Martin Pfeil (personal) <greg@technomadic.org>:::::::::
284uid:u::::1245341857::DCC83A1E17A088D1D646966017A54390D70F63C7::Gregory Martin Pfeil (Clozure Associates) <greg@clozure.com>:::::::::
285uid:u::::1245342043::D274624C55A6124E935928A0C0AAC0A45DF47AB5::Gregory Martin Pfeil (ITA Software) <gpfeil@itasoftware.com>:::::::::
286uid:u::::1149382607::34BDFD347FED57041E483973C27C4F5C6379E1A6::Gregory Martin Pfeil (Amazon.com) <pfeil@amazon.com>:::::::::
287uid:u::::1292846928::C9A8CEFCDA1CEF8706A5B815EE4027F1340F209F::Gregory Martin Pfeil (Rayservers) <greg@rayservers.net>:::::::::
288ssb:u:2048:16:35259A50693B4429:1149381489::::::e:::+:::
289fpr:::::::::82E14B2AF315373CFFA88C8335259A50693B4429:
290grp:::::::::36714469BDCD99CD5748B39D9463E3DD06BEE2CC:
291`
292
293const keyringRevokedID = `
294sec:u:256:22:851B3498422B2DFA:1491212600:::u:::scESC:::+::ed25519::
295fpr:::::::::582AB5DE7B6BB11F6E2B7075851B3498422B2DFA:
296grp:::::::::45712C069D5ECB349A11DE7C7155E66D1D3E9BC3:
297uid:u::::1491212618::999BA342C3370F86AAE7A163C67EA2518F69ECFE::This One WIll be rev0ked:::::::::
298uid:r::::::30EC553EACC420881282218E39CEDA11E722D937::Hello AA:::::::::
299ssb:u:256:18:151E2B742F97B843:1491212600::::::e:::+::cv25519:
300fpr:::::::::2DEBE37BF89745512A87C69D151E2B742F97B843:
301grp:::::::::788233E7043694A6C4D9DE4562FEC67972C0CBF9:
302`
303