aboutsummaryrefslogtreecommitdiff
path: root/cmd_verify.go
diff options
context:
space:
mode:
Diffstat (limited to 'cmd_verify.go')
-rw-r--r--cmd_verify.go183
1 files changed, 183 insertions, 0 deletions
diff --git a/cmd_verify.go b/cmd_verify.go
new file mode 100644
index 0000000..c38955d
--- /dev/null
+++ b/cmd_verify.go
@@ -0,0 +1,183 @@
+package main
+
+import (
+ "context"
+ "flag"
+ "fmt"
+ "io/ioutil"
+ "log"
+ "strings"
+
+ "dim13.org/signify/b64file"
+ "dim13.org/signify/key"
+ "dim13.org/signify/zsig"
+ "github.com/google/subcommands"
+)
+
+// Usage: signify -V [-eqz] [-p pubkey] [-t keytype] [-x sigfile] -m message
+
+type verifyCommand struct {
+ embedded bool
+ quiet bool
+ zip bool
+ pubFile string
+ keyFile string
+ sigFile string
+ msgFile string
+}
+
+func (v *verifyCommand) Name() string { return "verify" }
+func (v *verifyCommand) Synopsis() string { return "verify signature" }
+func (v *verifyCommand) Usage() string {
+ return "verify [-eqz] [-p pubkey] [-t keytype] [-x sigfile] -m message\n"
+}
+
+func (v *verifyCommand) SetFlags(f *flag.FlagSet) {
+ f.BoolVar(&v.embedded, "e", false, "embed message")
+ f.BoolVar(&v.quiet, "q", false, "quiet mode")
+ f.BoolVar(&v.zip, "z", false, "verify gzip archive") // TODO
+ f.StringVar(&v.pubFile, "p", "", "public key file")
+ f.StringVar(&v.keyFile, "t", "", "key type") // TODO
+ f.StringVar(&v.sigFile, "x", "", "signature file")
+ f.StringVar(&v.msgFile, "m", "", "message file (required)")
+}
+
+func (v *verifyCommand) Execute(ctx context.Context, f *flag.FlagSet, args ...interface{}) subcommands.ExitStatus {
+ if v.msgFile == "" {
+ f.Usage()
+ return subcommands.ExitUsageError
+ }
+ if v.sigFile == "" {
+ v.sigFile = SigName(v.msgFile)
+ }
+ // TODO keyType
+
+ switch {
+ case v.zip && v.embedded:
+ return subcommands.ExitUsageError
+ case v.zip:
+ if err := verifyGzip(v.pubFile, v.sigFile); err != nil {
+ log.Println(err)
+ return subcommands.ExitFailure
+ }
+ case v.embedded:
+ if err := verifyEmbedded(v.pubFile, v.sigFile); err != nil {
+ log.Println(err)
+ return subcommands.ExitFailure
+ }
+ default:
+ if err := verifyPlain(v.pubFile, v.sigFile, v.msgFile); err != nil {
+ log.Println(err)
+ return subcommands.ExitFailure
+ }
+ }
+ if !v.quiet {
+ fmt.Println("Signature Verified")
+ }
+ return subcommands.ExitSuccess
+}
+
+func verifyPlain(pubFile, sigFile, msgFile string) error {
+ msg, err := ioutil.ReadFile(msgFile)
+ if err != nil {
+ return err
+ }
+ sig, _, verifyWith, err := openSig(sigFile)
+ if err != nil {
+ return err
+ }
+ if pubFile == "" {
+ pubFile = verifyWith
+ }
+ pub, err := openPub(pubFile)
+ if err != nil {
+ return err
+ }
+ return sig.Verify(msg, pub)
+}
+
+func verifyEmbedded(pubFile, sigFile string) error {
+ sig, msg, verifyWith, err := openSig(sigFile)
+ if err != nil {
+ return err
+ }
+ if pubFile == "" {
+ pubFile = verifyWith
+ }
+ pub, err := openPub(pubFile)
+ if err != nil {
+ return err
+ }
+ return sig.Verify(msg, pub)
+}
+
+// TODO ugly work-in-progress
+func verifyGzip(pubFile, sigFile string) error {
+ fd, err := Open(sigFile)
+ if err != nil {
+ return err
+ }
+ defer fd.Close()
+ z, err := zsig.NewReader(fd)
+ if err != nil {
+ return err
+ }
+
+ sig := new(key.Sig)
+ _, msg, err := b64file.Decode(strings.NewReader(z.Comment), sig)
+ if err != nil {
+ return err
+ }
+ if err := sig.Validate(); err != nil {
+ return err
+ }
+
+ pub, err := openPub(pubFile)
+ if err != nil {
+ return err
+ }
+ if err := sig.Verify(msg, pub); err != nil {
+ return err
+ }
+
+ zhead, err := zsig.ParseBytes(msg)
+ if err != nil {
+ return err
+ }
+
+ return zhead.Verify(z)
+}
+
+func openPub(fname string) (*key.Pub, error) {
+ pub := new(key.Pub)
+ fd, err := Open(fname)
+ if err != nil {
+ return nil, err
+ }
+ defer fd.Close()
+ if _, _, err := b64file.Decode(fd, pub); err != nil {
+ return nil, err
+ }
+ if err := pub.Validate(); err != nil {
+ return nil, err
+ }
+ return pub, nil
+}
+
+func openSig(fname string) (*key.Sig, []byte, string, error) {
+ sig := new(key.Sig)
+ fd, err := Open(fname)
+ if err != nil {
+ return nil, nil, "", err
+ }
+ defer fd.Close()
+ comment, msg, err := b64file.Decode(fd, sig)
+ if err != nil {
+ return nil, nil, "", err
+ }
+ if err := sig.Validate(); err != nil {
+ return nil, nil, "", err
+ }
+ pubKey := CommentPubFile(comment)
+ return sig, msg, pubKey, nil
+}