github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/engine/pgp_export_key_test.go (about) 1 // Copyright 2015 Keybase, Inc. All rights reserved. Use of 2 // this source code is governed by the included BSD license. 3 4 package engine 5 6 import ( 7 "testing" 8 9 "github.com/stretchr/testify/require" 10 11 "github.com/keybase/client/go/libkb" 12 keybase1 "github.com/keybase/client/go/protocol/keybase1" 13 ) 14 15 func TestPGPExportOptions(t *testing.T) { 16 tc := SetupEngineTest(t, "pgpsave") 17 defer tc.Cleanup() 18 19 u := CreateAndSignupFakeUser(tc, "login") 20 secui := &libkb.TestSecretUI{Passphrase: u.Passphrase} 21 uis := libkb.UIs{LogUI: tc.G.UI.GetLogUI(), SecretUI: secui} 22 23 fp, kid, key := genPGPKeyAndArmor(t, tc, u.Email) 24 eng, err := NewPGPKeyImportEngineFromBytes(tc.G, []byte(key), true) 25 if err != nil { 26 t.Fatal(err) 27 } 28 m := NewMetaContextForTest(tc).WithUIs(uis) 29 if err = RunEngine2(m, eng); err != nil { 30 t.Fatal(err) 31 } 32 33 table := []exportTest{ 34 {true, fp.String(), false, 1, 1, 0}, 35 {true, fp.String(), true, 1, 1, 0}, 36 {false, fp.String(), false, 1, 1, 0}, 37 {false, fp.String(), true, 1, 1, 0}, 38 39 // fingerprint substring must be suffix: 40 {true, fp.String()[len(fp.String())-5:], false, 1, 1, 0}, 41 {true, fp.String()[len(fp.String())-5:], true, 0, 0, 0}, 42 {false, fp.String()[len(fp.String())-5:], false, 1, 1, 0}, 43 {false, fp.String()[len(fp.String())-5:], true, 0, 0, 0}, 44 {true, fp.String()[0:5], false, 0, 0, 0}, 45 {true, fp.String()[0:5], true, 0, 0, 0}, 46 {false, fp.String()[0:5], false, 0, 0, 0}, 47 {false, fp.String()[0:5], true, 0, 0, 0}, 48 49 {true, kid.String(), false, 1, 0, 1}, 50 {true, kid.String(), true, 1, 0, 1}, 51 {false, kid.String(), false, 1, 0, 1}, 52 {false, kid.String(), true, 1, 0, 1}, 53 54 // kid substring must be prefix: 55 {true, kid.String()[len(fp.String())-5:], false, 0, 0, 0}, 56 {true, kid.String()[len(fp.String())-5:], true, 0, 0, 0}, 57 {false, kid.String()[len(fp.String())-5:], false, 0, 0, 0}, 58 {false, kid.String()[len(fp.String())-5:], true, 0, 0, 0}, 59 {true, kid.String()[0:5], false, 1, 0, 1}, 60 {true, kid.String()[0:5], true, 0, 0, 0}, 61 {false, kid.String()[0:5], false, 1, 0, 1}, 62 {false, kid.String()[0:5], true, 0, 0, 0}, 63 } 64 65 for i, test := range table { 66 ec, err := pgpExport(m, test.secret, test.query, test.exact) 67 if err != nil { 68 t.Errorf("test %d error: %s", i, err) 69 } 70 if ec.either != test.either { 71 t.Errorf("test %d: (either) num keys exported: %d, expected %d", i, ec.either, test.either) 72 } 73 if ec.fingerprint != test.fingerprint { 74 t.Errorf("test %d: (fp) num keys exported: %d, expected %d", i, ec.fingerprint, test.fingerprint) 75 } 76 if ec.kid != test.kid { 77 t.Errorf("test %d: (kid) num keys exported: %d, expected %d", i, ec.kid, test.kid) 78 } 79 } 80 } 81 82 type exportTest struct { 83 secret bool 84 query string 85 exact bool 86 either int 87 fingerprint int 88 kid int 89 } 90 91 type exportCounts struct { 92 either int 93 fingerprint int 94 kid int 95 } 96 97 func pgpExport(m libkb.MetaContext, secret bool, query string, exact bool) (exportCounts, error) { 98 opts := keybase1.PGPQuery{ 99 Secret: secret, 100 Query: query, 101 ExactMatch: exact, 102 } 103 104 var xcount exportCounts 105 106 arg := keybase1.PGPExportArg{ 107 Options: opts, 108 } 109 g := m.G() 110 xe := NewPGPKeyExportEngine(g, arg) 111 if err := RunEngine2(m, xe); err != nil { 112 return xcount, err 113 } 114 115 xcount.either = len(xe.Results()) 116 117 farg := keybase1.PGPExportByFingerprintArg{ 118 Options: opts, 119 } 120 xf := NewPGPKeyExportByFingerprintEngine(g, farg) 121 if err := RunEngine2(m, xf); err != nil { 122 return xcount, err 123 } 124 125 xcount.fingerprint = len(xf.Results()) 126 127 karg := keybase1.PGPExportByKIDArg{ 128 Options: opts, 129 } 130 xk := NewPGPKeyExportByKIDEngine(g, karg) 131 if err := RunEngine2(m, xk); err != nil { 132 return xcount, err 133 } 134 135 xcount.kid = len(xk.Results()) 136 137 return xcount, nil 138 } 139 140 type PGPTestSecretUI struct { 141 libkb.TestSecretUI 142 Prompts []string 143 } 144 145 func (t *PGPTestSecretUI) GetPassphrase(p keybase1.GUIEntryArg, terminal *keybase1.SecretEntryArg) (keybase1.GetPassphraseRes, error) { 146 t.CalledGetPassphrase = true 147 t.Prompts = append(t.Prompts, p.Prompt) 148 return keybase1.GetPassphraseRes{ 149 Passphrase: t.Passphrase, 150 StoreSecret: t.StoreSecret, 151 }, nil 152 } 153 154 func TestPGPExportEncryption(t *testing.T) { 155 tc := SetupEngineTest(t, "pgpsave") 156 defer tc.Cleanup() 157 158 u := CreateAndSignupFakeUser(tc, "login") 159 160 pgpPassphrase := "hello_pgp" + u.Passphrase 161 secui := &PGPTestSecretUI{} 162 secui.Passphrase = pgpPassphrase 163 uis := libkb.UIs{LogUI: tc.G.UI.GetLogUI(), SecretUI: secui} 164 165 fp, _, key := genPGPKeyAndArmor(t, tc, u.Email) 166 eng, err := NewPGPKeyImportEngineFromBytes(tc.G, []byte(key), true) 167 require.NoError(t, err) 168 169 m := NewMetaContextForTest(tc).WithUIs(uis) 170 err = RunEngine2(m, eng) 171 require.NoError(t, err) 172 173 opts := keybase1.PGPQuery{ 174 Secret: true, 175 Query: fp.String(), 176 ExactMatch: true, 177 } 178 179 // Run export with Encrypted: true 180 181 arg := keybase1.PGPExportArg{ 182 Options: opts, 183 Encrypted: true, 184 } 185 xe := NewPGPKeyExportEngine(tc.G, arg) 186 if err := RunEngine2(m, xe); err != nil { 187 t.Fatal(err) 188 } 189 190 require.Len(t, secui.Prompts, 2, "Expected two prompts in SecretUI (PGP passphrase and confirmation)") 191 secui.Prompts = []string{} 192 193 entity, _, err := libkb.ReadOneKeyFromString(xe.Results()[0].Key) 194 require.NoError(t, err) 195 196 require.NotNil(t, entity.PrivateKey, "Key isn't private key") 197 require.True(t, entity.PrivateKey.Encrypted, "Key is not encrypted") 198 199 for i, subkey := range entity.Subkeys { 200 require.True(t, subkey.PrivateKey.Encrypted, "Subkey %d is not encrypted", i) 201 } 202 203 if err := entity.PrivateKey.Decrypt([]byte(pgpPassphrase)); err != nil { 204 t.Fatal("Decryption with passphrase failed") 205 } 206 207 // Run export with Encrypted: false 208 209 arg = keybase1.PGPExportArg{ 210 Options: opts, 211 Encrypted: false, 212 } 213 xe = NewPGPKeyExportEngine(tc.G, arg) 214 err = RunEngine2(m, xe) 215 require.NoError(t, err) 216 217 require.Len(t, secui.Prompts, 0, "Expected no prompts in SecretUI") 218 219 entity, _, err = libkb.ReadOneKeyFromString(xe.Results()[0].Key) 220 require.NoError(t, err) 221 222 require.NotNil(t, entity.PrivateKey, "Key isn't private key") 223 require.False(t, entity.PrivateKey.Encrypted, "Key is encrypted") 224 225 for i, subkey := range entity.Subkeys { 226 require.False(t, subkey.PrivateKey.Encrypted, "Subkey %d is encrypted", i) 227 } 228 } 229 230 func TestPGPExportMultipleSyncedKeys(t *testing.T) { 231 tc := SetupEngineTest(t, "pgpexport") 232 defer tc.Cleanup() 233 234 u := CreateAndSignupFakeUser(tc, "pgp") 235 236 secui := &PGPTestSecretUI{} 237 uis := libkb.UIs{LogUI: tc.G.UI.GetLogUI(), SecretUI: secui} 238 239 // Generate two keys and import with pushPrivate. 240 fps := make([]libkb.PGPFingerprint, 2) 241 for i := range fps { 242 fp, _, key := genPGPKeyAndArmor(t, tc, u.Email) 243 eng, err := NewPGPKeyImportEngineFromBytes(tc.G, []byte(key), true /* pushPrivate */) 244 require.NoError(t, err) 245 246 m := NewMetaContextForTest(tc).WithUIs(uis) 247 err = RunEngine2(m, eng) 248 require.NoError(t, err) 249 250 fps[i] = fp 251 } 252 253 // Purge PGP keys from local keychain so we are forced to fetch server 254 // synced keys. 255 { 256 eng := NewPGPPurge(tc.G, keybase1.PGPPurgeArg{ 257 DoPurge: true, 258 }) 259 m := NewMetaContextForTest(tc).WithUIs(uis) 260 err := RunEngine2(m, eng) 261 require.NoError(t, err) 262 } 263 264 t.Logf("Trying to export keys now") 265 266 // Try to export each key. 267 for _, fp := range fps { 268 arg := keybase1.PGPExportArg{ 269 Options: keybase1.PGPQuery{ 270 Secret: true, 271 Query: fp.String(), 272 ExactMatch: true, 273 }, 274 Encrypted: false, 275 } 276 eng := NewPGPKeyExportEngine(tc.G, arg) 277 m := NewMetaContextForTest(tc).WithUIs(uis) 278 err := RunEngine2(m, eng) 279 require.NoError(t, err) 280 281 require.Len(t, eng.Results(), 1) 282 283 entity, _, err := libkb.ReadOneKeyFromString(eng.Results()[0].Key) 284 require.NoError(t, err) 285 286 require.NotNil(t, entity.PrivateKey, "Key isn't private key") 287 require.Equal(t, fp, entity.GetFingerprint()) 288 } 289 }