From 8c250379fbf0ad8c756e18863c9c51c2d2073576 Mon Sep 17 00:00:00 2001 From: Scott Leggett Date: Mon, 26 Jul 2021 13:10:20 +0800 Subject: [PATCH] feat: factor out the touch notification for gpg signing too --- internal/assuan/assuan.go | 12 ++++++++---- internal/notify/touch.go | 31 +++++++++++++++++++++++++++++++ internal/ssh/agent.go | 22 ++-------------------- 3 files changed, 41 insertions(+), 24 deletions(-) create mode 100644 internal/notify/touch.go diff --git a/internal/assuan/assuan.go b/internal/assuan/assuan.go index c4d73bd..7e83083 100644 --- a/internal/assuan/assuan.go +++ b/internal/assuan/assuan.go @@ -16,6 +16,7 @@ import ( "github.com/smlx/fsm" "github.com/smlx/piv-agent/internal/gpg" + "github.com/smlx/piv-agent/internal/notify" "github.com/smlx/piv-agent/internal/pivservice" "golang.org/x/crypto/cryptobyte" "golang.org/x/crypto/cryptobyte/asn1" @@ -260,11 +261,14 @@ func hexDecode(data ...[]byte) ([][]byte, error) { // sign performs signing of the specified "hash" data, using the specified // "hashAlgo" hash algorithm. It then encodes the response into an s-expression // and returns it as a byte slice. +// +// This function's complexity is due to the fact that while Sign() returns the +// r and s components of the signature ASN1-encoded, gpg expects them to be +// separately s-exp encoded. So we have to decode the ASN1 signature, extract +// the params, and re-encode them into the s-exp. Ugh. func (a *Assuan) sign() ([]byte, error) { - // This function's complexity is due to the fact that while Sign() returns - // the r and s components of the signature ASN1-encoded, gpg expects them to - // be separately s-exp encoded. So we have to decode the ASN1 signature, - // extract the params, and re-encode them into the s-exp. Ugh. + cancel := notify.Touch(nil) + defer cancel() signature, err := a.signingPrivKey.Sign(rand.Reader, a.hash, a.hashAlgo) if err != nil { return nil, fmt.Errorf("couldn't sign: %v", err) diff --git a/internal/notify/touch.go b/internal/notify/touch.go new file mode 100644 index 0000000..4146605 --- /dev/null +++ b/internal/notify/touch.go @@ -0,0 +1,31 @@ +package notify + +import ( + "context" + "time" + + "github.com/gen2brain/beeep" + "go.uber.org/zap" +) + +const waitTime = 6 * time.Second + +// Touch starts a goroutine, and waits for a short period. If the returned +// CancelFunc has not been called it sends a notification to remind the user to +// physically touch the Security Key. +func Touch(log *zap.Logger) context.CancelFunc { + ctx, cancel := context.WithCancel(context.Background()) + timer := time.NewTimer(waitTime) + go func() { + select { + case <-ctx.Done(): + timer.Stop() + case <-timer.C: + err := beeep.Alert("Security Key Agent", "Waiting for touch...", "") + if err != nil && log != nil { + log.Warn("couldn't send touch notification", zap.Error(err)) + } + } + }() + return cancel +} diff --git a/internal/ssh/agent.go b/internal/ssh/agent.go index 2bb2cbf..f0cd370 100644 --- a/internal/ssh/agent.go +++ b/internal/ssh/agent.go @@ -2,7 +2,6 @@ package ssh import ( "bytes" - "context" "crypto/rand" "errors" "fmt" @@ -10,9 +9,8 @@ import ( "os" "path/filepath" "sync" - "time" - "github.com/gen2brain/beeep" + "github.com/smlx/piv-agent/internal/notify" pinentry "github.com/smlx/piv-agent/internal/pinentry" "github.com/smlx/piv-agent/internal/pivservice" "go.uber.org/zap" @@ -146,9 +144,8 @@ func (a *Agent) signWithSigners(key gossh.PublicKey, data []byte, signers []goss continue } // (possibly) send a notification - ctx, cancel := context.WithCancel(context.Background()) + cancel := notify.Touch(a.log) defer cancel() - a.touchNotify(ctx) // perform signature a.log.Debug("signing", zap.Binary("public key bytes", s.PublicKey().Marshal())) @@ -157,21 +154,6 @@ func (a *Agent) signWithSigners(key gossh.PublicKey, data []byte, signers []goss return nil, fmt.Errorf("%w: %v", ErrUnknownKey, key) } -func (a *Agent) touchNotify(ctx context.Context) { - timer := time.NewTimer(8 * time.Second) - go func() { - select { - case <-ctx.Done(): - timer.Stop() - case <-timer.C: - err := beeep.Alert("Security Key Agent", "Waiting for touch...", "") - if err != nil { - a.log.Warn("couldn't send touch notification", zap.Error(err)) - } - } - }() -} - // Add adds a private key to the agent. func (a *Agent) Add(key agent.AddedKey) error { return ErrNotImplemented