1// Copyright 2016 Keybase, Inc. All rights reserved. Use of
2// this source code is governed by the included BSD license.
3
4package engine
5
6import (
7	"github.com/keybase/client/go/libkb"
8	keybase1 "github.com/keybase/client/go/protocol/keybase1"
9)
10
11// PGPKeyGen is an engine.
12type PGPKeyGen struct {
13	libkb.Contextified
14	arg    keybase1.PGPKeyGenDefaultArg
15	genArg *libkb.PGPGenArg
16}
17
18// NewPGPKeyGen creates a PGPKeyGen engine.
19func NewPGPKeyGen(g *libkb.GlobalContext, arg keybase1.PGPKeyGenDefaultArg) *PGPKeyGen {
20	return &PGPKeyGen{
21		Contextified: libkb.NewContextified(g),
22		arg:          arg,
23	}
24}
25
26// Name is the unique engine name.
27func (e *PGPKeyGen) Name() string {
28	return "PGPKeyGen"
29}
30
31// GetPrereqs returns the engine prereqs.
32func (e *PGPKeyGen) Prereqs() Prereqs {
33	return Prereqs{
34		Device: true,
35	}
36}
37
38// RequiredUIs returns the required UIs.
39func (e *PGPKeyGen) RequiredUIs() []libkb.UIKind {
40	return []libkb.UIKind{
41		libkb.PgpUIKind,
42		libkb.SecretUIKind,
43	}
44}
45
46// SubConsumers returns the other UI consumers for this engine.
47func (e *PGPKeyGen) SubConsumers() []libkb.UIConsumer {
48	return []libkb.UIConsumer{
49		&PGPKeyImportEngine{},
50	}
51}
52
53// Run starts the engine.
54func (e *PGPKeyGen) Run(m libkb.MetaContext) error {
55
56	// generate a new pgp key with defaults (and no push)
57	var genArg libkb.PGPGenArg
58	if e.genArg != nil {
59		genArg = *e.genArg
60	}
61	genArg.Ids = libkb.ImportPGPIdentities(e.arg.CreateUids.Ids)
62	arg := PGPKeyImportEngineArg{
63		AllowMulti: true,
64		OnlySave:   true,
65		Gen:        &genArg,
66	}
67	eng := NewPGPKeyImportEngine(m.G(), arg)
68	if err := RunEngine2(m, eng); err != nil {
69		return err
70	}
71
72	// tell the UI about the key
73	m.Debug("generated pgp key: %s", eng.bundle.GetFingerprint())
74	pub, err := eng.bundle.Encode()
75	if err != nil {
76		return err
77	}
78	keyArg := keybase1.KeyGeneratedArg{
79		Kid: eng.bundle.GetKID(),
80		Key: keybase1.KeyInfo{
81			Fingerprint: eng.bundle.GetFingerprint().String(),
82			Key:         pub,
83			Desc:        eng.bundle.VerboseDescription(),
84		},
85	}
86	if err := m.UIs().PgpUI.KeyGenerated(m.Ctx(), keyArg); err != nil {
87		return err
88	}
89
90	// ask if we should push private key to api server if user has a password
91	passphraseState, err := libkb.LoadPassphraseState(m)
92	if err != nil {
93		return err
94	}
95	pushPrivate, err := m.UIs().PgpUI.ShouldPushPrivate(m.Ctx(), keybase1.ShouldPushPrivateArg{
96		SessionID: m.UIs().SessionID,
97		Prompt:    passphraseState == keybase1.PassphraseState_KNOWN,
98	})
99	if err != nil {
100		return err
101	}
102
103	m.Debug("push private generated pgp key to API server? %v", pushPrivate)
104	if err := e.push(m, eng.bundle, pushPrivate); err != nil {
105		return err
106	}
107
108	// tell ui everything finished
109	return m.UIs().PgpUI.Finished(m.Ctx(), m.UIs().SessionID)
110}
111
112func (e *PGPKeyGen) push(m libkb.MetaContext, bundle *libkb.PGPKeyBundle, pushPrivate bool) (err error) {
113	defer m.Trace("PGPKeyGen.push", &err)()
114
115	me, err := libkb.LoadMe(libkb.NewLoadUserArgWithMetaContext(m).WithPublicKeyOptional())
116	if err != nil {
117		return err
118	}
119
120	del := &libkb.Delegator{
121		Me:             me,
122		Expire:         libkb.KeyExpireIn,
123		DelegationType: libkb.DelegationTypeSibkey,
124		Contextified:   libkb.NewContextified(m.G()),
125	}
126	if err := del.LoadSigningKey(m, m.UIs().SecretUI); err != nil {
127		return err
128	}
129	del.NewKey = bundle
130
131	if pushPrivate {
132		tsec, gen, err := libkb.GetTriplesecMaybePrompt(m)
133		if err != nil {
134			return err
135		}
136
137		skb, err := bundle.ToServerSKB(m.G(), tsec, gen)
138		if err != nil {
139			return err
140		}
141
142		armored, err := skb.ArmoredEncode()
143		if err != nil {
144			return err
145		}
146		del.EncodedPrivateKey = armored
147	}
148
149	return del.Run(m)
150}
151