ogvt/main.go

123 lines
2.8 KiB
Go
Raw Normal View History

2020-02-06 08:09:47 -07:00
package main
import (
"bytes"
2020-02-06 08:09:47 -07:00
"flag"
"fmt"
"io"
"io/ioutil"
2020-02-06 08:09:47 -07:00
"os"
2020-11-16 08:27:40 -07:00
"path/filepath"
2020-02-06 08:09:47 -07:00
"golang.org/x/crypto/openpgp"
"golang.org/x/crypto/openpgp/clearsign"
2020-05-09 07:39:43 -06:00
"suah.dev/protect"
2020-02-06 08:09:47 -07:00
)
func errExit(err error) {
2020-02-06 08:09:47 -07:00
if err != nil {
if err == io.EOF {
fmt.Println("invalid signature file")
2020-02-15 17:21:31 -07:00
} else {
fmt.Println(err)
}
2020-02-06 08:09:47 -07:00
os.Exit(1)
}
}
var flags struct {
sig, file, pub string
}
2020-02-06 08:09:47 -07:00
func main() {
_ = protect.Pledge("stdio unveil rpath")
flag.StringVar(&flags.sig, "sig", "",
"path to signature file; if file contains cleartext message\n"+
"with signature, -file must be unset")
flag.StringVar(&flags.file, "file", "",
"path to unsigned message file; incompatible with cleartext\n"+
"signatures")
flag.StringVar(&flags.pub, "pub", "", "path to pubkey file")
2020-02-06 08:09:47 -07:00
flag.Parse()
2021-01-13 07:41:25 -07:00
if len(os.Args) == 1 {
flag.PrintDefaults()
os.Exit(1)
}
_ = protect.Unveil(flags.sig, "r")
_ = protect.Unveil(flags.file, "r")
_ = protect.Unveil(flags.pub, "r")
ext := filepath.Ext(flags.sig)
var signoext string
if flags.file == "" && ext != "" {
signoext = flags.sig[:len(flags.sig)-len(ext)]
_ = protect.Unveil(signoext, "r")
2020-11-16 08:27:40 -07:00
}
_ = protect.UnveilBlock()
2020-11-16 08:27:40 -07:00
pubFi, err := os.Open(flags.pub)
errExit(err)
defer pubFi.Close()
kr, err := openpgp.ReadArmoredKeyRing(pubFi)
if err != nil {
fmt.Printf("Can't parse public key %q\n%s\n", flags.pub, err)
os.Exit(1)
}
var sig, message io.Reader
var clearsigBlock *clearsign.Block
var armored bool
clearsigned := func(data []byte) bool {
clearsigBlock, _ = clearsign.Decode(data)
return clearsigBlock != nil
}
sigBytes, err := ioutil.ReadFile(flags.sig)
errExit(err)
switch {
case clearsigned(sigBytes):
if flags.file != "" {
fmt.Printf("-file is incompatible with cleartext signatures\n")
os.Exit(1)
}
message = bytes.NewReader(clearsigBlock.Bytes)
sig = clearsigBlock.ArmoredSignature.Body
armored = false // Body provides decoded signature
case flags.file == "":
// Check for a message file with the .sig extensions removed
flags.file = signoext
fallthrough
default:
messageFi, err := os.Open(flags.file)
if os.IsNotExist(err) {
fmt.Printf("signature %s does not provide cleartext, and no "+
"message %s found\n", flags.sig, flags.file)
os.Exit(1)
}
errExit(err)
defer messageFi.Close()
message = messageFi
sig = bytes.NewReader(sigBytes)
// Unless signature file uses .gpg or .sig extensions, read
// ascii armored input. This covers .asc signatures, and
// assumes armoring if the extension is otherwise unknown.
armored = ext != ".gpg" && ext != ".sig"
}
2020-02-06 08:09:47 -07:00
var ent *openpgp.Entity
if armored {
ent, err = openpgp.CheckArmoredDetachedSignature(kr, message, sig)
} else {
ent, err = openpgp.CheckDetachedSignature(kr, message, sig)
}
errExit(err)
2020-02-06 08:09:47 -07:00
for _, id := range ent.Identities {
2020-02-07 09:14:48 -07:00
fmt.Printf("%q\n", id.Name)
2020-02-06 08:09:47 -07:00
}
fmt.Println("Signature OK.")
}