diff options
author | Drew DeVault <sir@cmpwn.com> | 2018-01-31 21:54:52 -0500 |
---|---|---|
committer | Drew DeVault <sir@cmpwn.com> | 2018-01-31 21:54:52 -0500 |
commit | 3139148c7b9ad6ed4fb9cd8cd3e4160a9b9ee46f (patch) | |
tree | 1bb500628bae5f6b64167e498b25ff09649a977c /worker | |
parent | a21afdaa6bab8f6d05bbe9272700eef571548a59 (diff) |
Add certificate approval flow
Diffstat (limited to 'worker')
-rw-r--r-- | worker/imap/worker.go | 81 | ||||
-rw-r--r-- | worker/types/messages.go | 26 |
2 files changed, 73 insertions, 34 deletions
diff --git a/worker/imap/worker.go b/worker/imap/worker.go index d3ef715..ceff34d 100644 --- a/worker/imap/worker.go +++ b/worker/imap/worker.go @@ -1,12 +1,13 @@ package imap import ( + "crypto/tls" + "crypto/x509" "fmt" "log" "net/url" "strings" - "github.com/davecgh/go-spew/spew" "github.com/emersion/go-imap" "github.com/emersion/go-imap-idle" "github.com/emersion/go-imap/client" @@ -54,6 +55,45 @@ func (w *IMAPWorker) PostAction(msg types.WorkerMessage) { w.actions <- msg } +func (w *IMAPWorker) postMessage(msg types.WorkerMessage) { + w.logger.Printf("=> %T\n", msg) + w.messages <- msg +} + +func (w *IMAPWorker) verifyPeerCert(msg types.WorkerMessage) func( + rawCerts [][]byte, _ [][]*x509.Certificate) error { + + return func(rawCerts [][]byte, _ [][]*x509.Certificate) error { + pool := x509.NewCertPool() + for _, rawCert := range rawCerts { + cert, err := x509.ParseCertificate(rawCert) + if err != nil { + return err + } + pool.AddCert(cert) + } + + request := types.ApproveCertificate{ + Message: types.RespondTo(msg), + CertPool: pool, + } + w.postMessage(request) + + response := <-w.actions + if response.InResponseTo() != request { + return fmt.Errorf("Expected UI to answer cert request") + } + switch response.(type) { + case types.Ack: + return nil + case types.Disconnect: + return fmt.Errorf("UI rejected certificate") + default: + return fmt.Errorf("Expected UI to answer cert request") + } + } +} + func (w *IMAPWorker) handleMessage(msg types.WorkerMessage) error { switch msg := msg.(type) { case types.Ping: @@ -78,12 +118,14 @@ func (w *IMAPWorker) handleMessage(msg types.WorkerMessage) error { w.config.scheme = u.Scheme w.config.user = u.User case types.Connect: - // TODO: populate TLS config - var ( c *client.Client err error ) + tlsConfig := &tls.Config{ + InsecureSkipVerify: true, + VerifyPeerCertificate: w.verifyPeerCert(&msg), + } switch w.config.scheme { case "imap": c, err = client.Dial(w.config.addr) @@ -92,12 +134,12 @@ func (w *IMAPWorker) handleMessage(msg types.WorkerMessage) error { } if !w.config.insecure { - if err := c.StartTLS(nil); err != nil { + if err := c.StartTLS(tlsConfig); err != nil { return err } } case "imaps": - c, err = client.DialTLS(w.config.addr, nil) + c, err = client.DialTLS(w.config.addr, tlsConfig) if err != nil { return err } @@ -131,40 +173,27 @@ func (w *IMAPWorker) handleMessage(msg types.WorkerMessage) error { return nil } -// Logs an action but censors passwords -func (w *IMAPWorker) logAction(msg types.WorkerMessage) { - switch msg := msg.(type) { - case types.Configure: - src := msg.Config.Source - msg.Config.Source = "[obsfucated]" - w.logger.Printf("<= %s", spew.Sdump(msg)) - msg.Config.Source = src - default: - w.logger.Printf("<= %s", spew.Sdump(msg)) - } -} - func (w *IMAPWorker) Run() { for { select { case msg := <-w.actions: - w.logAction(msg) + w.logger.Printf("<= %T\n", msg) if err := w.handleMessage(msg); err == errUnsupported { - w.messages <- types.Unsupported{ + w.postMessage(types.Unsupported{ Message: types.RespondTo(msg), - } + }) } else if err != nil { - w.messages <- types.Error{ + w.postMessage(types.Error{ Message: types.RespondTo(msg), Error: err, - } + }) } else { - w.messages <- types.Ack{ + w.postMessage(types.Ack{ Message: types.RespondTo(msg), - } + }) } case update := <-w.updates: - w.logger.Printf("[= %s", spew.Sdump(update)) + w.logger.Printf("[= %T", update) } } } diff --git a/worker/types/messages.go b/worker/types/messages.go index e83bd6b..5259342 100644 --- a/worker/types/messages.go +++ b/worker/types/messages.go @@ -1,6 +1,8 @@ package types import ( + "crypto/x509" + "git.sr.ht/~sircmpwn/aerc2/config" ) @@ -12,6 +14,16 @@ type Message struct { inResponseTo WorkerMessage } +func RespondTo(msg WorkerMessage) Message { + return Message{ + inResponseTo: msg, + } +} + +func (m Message) InResponseTo() WorkerMessage { + return m.inResponseTo +} + // Meta-messages type Ack struct { @@ -27,7 +39,7 @@ type Unsupported struct { Message } -// Commands +// Actions type Ping struct { Message @@ -46,12 +58,10 @@ type Disconnect struct { Message } -func RespondTo(msg WorkerMessage) Message { - return Message{ - inResponseTo: msg, - } -} +// Messages -func (m Message) InResponseTo() WorkerMessage { - return m.inResponseTo +// Respond with an Ack to approve or Disconnect to reject +type ApproveCertificate struct { + Message + CertPool *x509.CertPool } |