Skip to content

Commit

Permalink
Add --if-unsigned option to sign commands
Browse files Browse the repository at this point in the history
  • Loading branch information
mtharp committed Jul 5, 2018
1 parent a30bc1d commit 26683a4
Show file tree
Hide file tree
Showing 11 changed files with 76 additions and 15 deletions.
20 changes: 19 additions & 1 deletion cmdline/remotecmd/signcmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,18 @@ var SignCmd = &cobra.Command{
RunE: signCmd,
}

var argSigType string
var (
argIfUnsigned bool
argSigType string
)

func init() {
RemoteCmd.AddCommand(SignCmd)
SignCmd.Flags().StringVarP(&argKeyName, "key", "k", "", "Name of key on remote server to use")
SignCmd.Flags().StringVarP(&argFile, "file", "f", "", "Input file to sign")
SignCmd.Flags().StringVarP(&argOutput, "output", "o", "", "Output file. Defaults to same as --file.")
SignCmd.Flags().StringVarP(&argSigType, "sig-type", "T", "", "Specify signature type (default: auto-detect)")
SignCmd.Flags().BoolVar(&argIfUnsigned, "if-unsigned", false, "Skip signing if the file already has a signature")
shared.AddDigestFlag(SignCmd)
shared.AddLateHook(func() {
signers.MergeFlags(SignCmd.Flags())
Expand Down Expand Up @@ -70,6 +74,9 @@ func signCmd(cmd *cobra.Command, args []string) (err error) {
}
var infile *os.File
if argFile == "-" {
if argIfUnsigned {
return shared.Fail(errors.New("cannot use --if-unsigned with standard input"))
}
if !mod.AllowStdin {
return shared.Fail(errors.New("this signature type does not support reading from stdin"))
}
Expand All @@ -86,6 +93,17 @@ func signCmd(cmd *cobra.Command, args []string) (err error) {
}
defer infile.Close()
}
if argIfUnsigned {
if signed, err := mod.IsSigned(infile); err != nil {
return shared.Fail(err)
} else if signed {
fmt.Fprintf(os.Stderr, "skipping already-signed file: %s\n", argFile)
return nil
}
if _, err := infile.Seek(0, 0); err != nil {
return shared.Fail(fmt.Errorf("failed to rewind input file: %s", err))
}
}
// transform input if needed
hash, err := shared.GetDigest()
if err != nil {
Expand Down
17 changes: 15 additions & 2 deletions cmdline/token/signcmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,9 @@ var SignCmd = &cobra.Command{
}

var (
argSigType string
argOutput string
argIfUnsigned bool
argSigType string
argOutput string
)

func init() {
Expand All @@ -46,6 +47,7 @@ func init() {
SignCmd.Flags().StringVarP(&argFile, "file", "f", "", "Input file to sign")
SignCmd.Flags().StringVarP(&argOutput, "output", "o", "", "Output file")
SignCmd.Flags().StringVarP(&argSigType, "sig-type", "T", "", "Specify signature type (default: auto-detect)")
SignCmd.Flags().BoolVar(&argIfUnsigned, "if-unsigned", false, "Skip signing if the file already has a signature")
shared.AddDigestFlag(SignCmd)
shared.AddLateHook(func() {
signers.MergeFlags(SignCmd.Flags())
Expand Down Expand Up @@ -88,6 +90,17 @@ func signCmd(cmd *cobra.Command, args []string) error {
return shared.Fail(err)
}
defer infile.Close()
if argIfUnsigned {
if signed, err := mod.IsSigned(infile); err != nil {
return shared.Fail(err)
} else if signed {
fmt.Fprintf(os.Stderr, "skipping already-signed file: %s\n", argFile)
return nil
}
if _, err := infile.Seek(0, 0); err != nil {
return shared.Fail(fmt.Errorf("failed to rewind input file: %s", err))
}
}
// transform the input, sign the stream, and apply the result
transform, err := mod.GetTransform(infile, *opts)
if err != nil {
Expand Down
4 changes: 4 additions & 0 deletions cmdline/verify/verify.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"github.com/sassoftware/relic/cmdline/shared"
"github.com/sassoftware/relic/lib/certloader"
"github.com/sassoftware/relic/lib/magic"
"github.com/sassoftware/relic/lib/pgptools"
"github.com/sassoftware/relic/lib/x509tools"
"github.com/sassoftware/relic/signers"
"github.com/spf13/cobra"
Expand Down Expand Up @@ -108,6 +109,9 @@ func verifyOne(path string, opts signers.VerifyOpts) error {
sigs, err = mod.Verify(f, opts)
}
if err != nil {
if _, ok := err.(pgptools.ErrNoKey); ok {
return fmt.Errorf("%s; use --cert to specify known keys", err)
}
return err
}
for _, sig := range sigs {
Expand Down
9 changes: 8 additions & 1 deletion lib/appmanifest/verify.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"github.com/sassoftware/relic/lib/pkcs9"
"github.com/sassoftware/relic/lib/x509tools"
"github.com/sassoftware/relic/lib/xmldsig"
"github.com/sassoftware/relic/signers/sigerrors"
)

type ManifestSignature struct {
Expand All @@ -46,14 +47,20 @@ func Verify(manifest []byte) (*ManifestSignature, error) {
root := doc.Root()
primary, err := xmldsig.Verify(root, "Signature", nil)
if err != nil {
if _, ok := err.(sigerrors.NotSignedError); ok {
return nil, err
}
return nil, fmt.Errorf("invalid primary signature: %s", err)
}
license := root.FindElement("Signature/KeyInfo/msrel:RelData/r:license")
if license == nil {
return nil, fmt.Errorf("invalid authenticode signature: %s", "signature is missing")
return nil, sigerrors.NotSignedError{Type: "application manifest"}
}
secondary, err := xmldsig.Verify(license, "issuer/Signature", nil)
if err != nil {
if _, ok := err.(sigerrors.NotSignedError); ok {
return nil, err
}
return nil, fmt.Errorf("invalid authenticode signature: %s", err)
}
if !x509tools.SameKey(primary.PublicKey, secondary.PublicKey) {
Expand Down
3 changes: 2 additions & 1 deletion lib/authenticode/peverify.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
"github.com/sassoftware/relic/lib/pkcs7"
"github.com/sassoftware/relic/lib/pkcs9"
"github.com/sassoftware/relic/lib/x509tools"
"github.com/sassoftware/relic/signers/sigerrors"
)

type PESignature struct {
Expand All @@ -46,7 +47,7 @@ func VerifyPE(r io.ReadSeeker, skipDigests bool) ([]PESignature, error) {
if err != nil {
return nil, err
} else if hvals.certSize == 0 {
return nil, errors.New("image does not contain any signatures")
return nil, sigerrors.NotSignedError{Type: "PECOFF"}
}
// Read certificate table
sigblob := make([]byte, hvals.certSize)
Expand Down
3 changes: 2 additions & 1 deletion lib/xmldsig/verify.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
"strings"

"github.com/sassoftware/relic/lib/x509tools"
"github.com/sassoftware/relic/signers/sigerrors"

"github.com/beevik/etree"
)
Expand All @@ -56,7 +57,7 @@ func Verify(root *etree.Element, sigpath string, extraCerts []*x509.Certificate)
root = root.Copy()
sigs := root.FindElements(sigpath)
if len(sigs) == 0 {
return nil, errors.New("xmldsig: signature not found")
return nil, sigerrors.NotSignedError{Type: "xmldsig"}
} else if len(sigs) > 1 {
return nil, errors.New("xmldsig: multiple signatures found")
}
Expand Down
5 changes: 1 addition & 4 deletions signers/deb/signer.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import (
"github.com/sassoftware/relic/lib/audit"
"github.com/sassoftware/relic/lib/certloader"
"github.com/sassoftware/relic/lib/magic"
"github.com/sassoftware/relic/lib/pgptools"
"github.com/sassoftware/relic/lib/signdeb"
"github.com/sassoftware/relic/signers"
"github.com/sassoftware/relic/signers/sigerrors"
Expand Down Expand Up @@ -71,9 +70,7 @@ func sign(r io.Reader, cert *certloader.Certificate, opts signers.SignOpts) ([]b

func verify(f *os.File, opts signers.VerifyOpts) ([]*signers.Signature, error) {
sigmap, err := signdeb.Verify(f, opts.TrustedPgp, opts.NoDigests)
if _, ok := err.(pgptools.ErrNoKey); ok {
return nil, fmt.Errorf("%s; use --cert to specify known keys", err)
} else if err != nil {
if err != nil {
return nil, err
}
if len(sigmap) == 0 {
Expand Down
2 changes: 0 additions & 2 deletions signers/pgp/signer.go
Original file line number Diff line number Diff line change
Expand Up @@ -214,8 +214,6 @@ func verifyPgp(sig *pgptools.PgpSignature, name string, err error) ([]*signers.S
}}, nil
} else if sig != nil {
return nil, fmt.Errorf("bad signature from %s(%x) [%s]: %s", pgptools.EntityName(sig.Key.Entity), sig.Key.PublicKey.KeyId, sig.CreationTime, err)
} else if _, ok := err.(pgptools.ErrNoKey); ok {
return nil, fmt.Errorf("%s; use --cert to specify known keys", err)
}
return nil, err
}
3 changes: 2 additions & 1 deletion signers/rpm/signer.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
"github.com/sassoftware/relic/lib/binpatch"
"github.com/sassoftware/relic/lib/certloader"
"github.com/sassoftware/relic/lib/magic"
"github.com/sassoftware/relic/lib/pgptools"
"github.com/sassoftware/relic/signers"
"github.com/sassoftware/relic/signers/sigerrors"
)
Expand Down Expand Up @@ -102,7 +103,7 @@ func verify(f *os.File, opts signers.VerifyOpts) ([]*signers.Signature, error) {
}
if sig.Signer == nil {
if !opts.NoChain {
return nil, fmt.Errorf("unknown keyId %x; use --cert to specify known keys", sig.KeyId)
return nil, pgptools.ErrNoKey(sig.KeyId)
}
rsig.Signer = fmt.Sprintf("UNKNOWN(%x)", sig.KeyId)
} else {
Expand Down
23 changes: 23 additions & 0 deletions signers/signers.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (
"github.com/sassoftware/relic/lib/pgptools"
"github.com/sassoftware/relic/lib/pkcs9"
"github.com/sassoftware/relic/lib/x509tools"
"github.com/sassoftware/relic/signers/sigerrors"
"golang.org/x/crypto/openpgp"
)

Expand Down Expand Up @@ -190,3 +191,25 @@ func MergeFlags(fs *pflag.FlagSet) {
})
}
}

// IsSigned checks if a file contains a signature
func (s *Signer) IsSigned(f *os.File) (bool, error) {
var err error
if s.VerifyStream != nil {
_, err = s.VerifyStream(f, VerifyOpts{NoDigests: true, NoChain: true})
} else if s.Verify != nil {
_, err = s.Verify(f, VerifyOpts{NoDigests: true, NoChain: true})
} else {
return false, errors.New("cannot check if this type of file is signed")
}
if err == nil {
return true, nil
}
switch err.(type) {
case sigerrors.NotSignedError:
return false, nil
case pgptools.ErrNoKey:
return true, nil
}
return false, err
}
2 changes: 0 additions & 2 deletions signers/starman/signer.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,6 @@ func verify(r io.Reader, opts signers.VerifyOpts) ([]*signers.Signature, error)
}}, nil
} else if sig != nil {
return nil, fmt.Errorf("bad signature from %s(%x) [%s]: %s", pgptools.EntityName(sig.Key.Entity), sig.Key.PublicKey.KeyId, sig.CreationTime, err)
} else if _, ok := err.(pgptools.ErrNoKey); ok {
return nil, fmt.Errorf("%s; use --cert to specify known keys", err)
}
return nil, err
}

0 comments on commit 26683a4

Please sign in to comment.