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 }