...

Source file src/github.com/sassoftware/relic/cmdline/verify/verify.go

Documentation: github.com/sassoftware/relic/cmdline/verify

     1  //
     2  // Copyright (c) SAS Institute Inc.
     3  //
     4  // Licensed under the Apache License, Version 2.0 (the "License");
     5  // you may not use this file except in compliance with the License.
     6  // You may obtain a copy of the License at
     7  //
     8  //     http://www.apache.org/licenses/LICENSE-2.0
     9  //
    10  // Unless required by applicable law or agreed to in writing, software
    11  // distributed under the License is distributed on an "AS IS" BASIS,
    12  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  // See the License for the specific language governing permissions and
    14  // limitations under the License.
    15  //
    16  
    17  package verify
    18  
    19  import (
    20  	"crypto/x509"
    21  	"errors"
    22  	"fmt"
    23  	"os"
    24  
    25  	"github.com/sassoftware/relic/cmdline/shared"
    26  	"github.com/sassoftware/relic/lib/certloader"
    27  	"github.com/sassoftware/relic/lib/magic"
    28  	"github.com/sassoftware/relic/lib/pgptools"
    29  	"github.com/sassoftware/relic/lib/x509tools"
    30  	"github.com/sassoftware/relic/signers"
    31  	"github.com/spf13/cobra"
    32  )
    33  
    34  var VerifyCmd = &cobra.Command{
    35  	Use:   "verify",
    36  	Short: "Verify a signed package or executable",
    37  	RunE:  verifyCmd,
    38  }
    39  
    40  var (
    41  	argNoIntegrityCheck bool
    42  	argNoChain          bool
    43  	argAlsoSystem       bool
    44  	argContent          string
    45  	argTrustedCerts     []string
    46  )
    47  
    48  func init() {
    49  	shared.RootCmd.AddCommand(VerifyCmd)
    50  	VerifyCmd.Flags().BoolVar(&argNoIntegrityCheck, "no-integrity-check", false, "Bypass the integrity check of the file contents and only inspect the signature itself")
    51  	VerifyCmd.Flags().BoolVar(&argNoChain, "no-trust-chain", false, "Do not test whether the signing certificate is trusted")
    52  	VerifyCmd.Flags().BoolVar(&argAlsoSystem, "system-store", false, "When --cert is used, append rather than replace the system trust store")
    53  	VerifyCmd.Flags().StringVar(&argContent, "content", "", "Specify file containing contents for detached signatures")
    54  	VerifyCmd.Flags().StringArrayVar(&argTrustedCerts, "cert", nil, "Add a trusted root certificate (PEM, DER, PKCS#7, or PGP)")
    55  }
    56  
    57  func verifyCmd(cmd *cobra.Command, args []string) error {
    58  	if len(args) == 0 {
    59  		return errors.New("Expected 1 or more files")
    60  	}
    61  	opts, err := loadCerts()
    62  	if err != nil {
    63  		return err
    64  	}
    65  	rc := 0
    66  	for _, path := range args {
    67  		if err := verifyOne(path, opts); err != nil {
    68  			fmt.Printf("%s ERROR: %s\n", path, err)
    69  			rc = 1
    70  		}
    71  	}
    72  	if rc != 0 {
    73  		fmt.Fprintln(os.Stderr, "ERROR: 1 or more files did not validate")
    74  	}
    75  	os.Exit(rc)
    76  	return nil
    77  }
    78  
    79  func verifyOne(path string, opts signers.VerifyOpts) error {
    80  	f, err := shared.OpenFile(path)
    81  	if err != nil {
    82  		return err
    83  	}
    84  	defer f.Close()
    85  	fileType, compression := magic.DetectCompressed(f)
    86  	opts.FileName = path
    87  	opts.Compression = compression
    88  	if _, err := f.Seek(0, 0); err != nil {
    89  		return err
    90  	}
    91  	mod := signers.ByMagic(fileType)
    92  	if mod == nil {
    93  		mod = signers.ByFileName(path)
    94  	}
    95  	if mod == nil {
    96  		return errors.New("unknown filetype")
    97  	}
    98  	var sigs []*signers.Signature
    99  	if mod.VerifyStream != nil {
   100  		r, err2 := magic.Decompress(f, opts.Compression)
   101  		if err2 != nil {
   102  			return err
   103  		}
   104  		sigs, err = mod.VerifyStream(r, opts)
   105  	} else {
   106  		if opts.Compression != magic.CompressedNone {
   107  			return errors.New("cannot verify compressed file")
   108  		}
   109  		sigs, err = mod.Verify(f, opts)
   110  	}
   111  	if err != nil {
   112  		if _, ok := err.(pgptools.ErrNoKey); ok {
   113  			return fmt.Errorf("%s; use --cert to specify known keys", err)
   114  		}
   115  		return err
   116  	}
   117  	for _, sig := range sigs {
   118  		var si, pkg, ts string
   119  		if sig.SigInfo != "" {
   120  			si = " " + sig.SigInfo + ":"
   121  		}
   122  		if sig.Package != "" {
   123  			pkg = sig.Package + " "
   124  		}
   125  		if sig.X509Signature != nil && !opts.NoChain {
   126  			if err := sig.X509Signature.VerifyChain(opts.TrustedPool, nil, x509.ExtKeyUsageAny); err != nil {
   127  				return err
   128  			}
   129  		}
   130  		if sig.X509Signature != nil && sig.X509Signature.CounterSignature != nil {
   131  			fmt.Printf("%s: OK -%s %s%s\n", path, si, pkg, sig.SignerName())
   132  			fmt.Printf("%s(timestamp): OK - `%s` [%s]\n", path, x509tools.FormatSubject(sig.X509Signature.CounterSignature.Certificate), sig.X509Signature.CounterSignature.SigningTime)
   133  		} else {
   134  			if !sig.CreationTime.IsZero() {
   135  				ts = fmt.Sprintf(" [%s]", sig.CreationTime)
   136  			}
   137  			fmt.Printf("%s: OK -%s %s%s%s\n", path, si, pkg, sig.SignerName(), ts)
   138  		}
   139  	}
   140  	return nil
   141  }
   142  
   143  func loadCerts() (signers.VerifyOpts, error) {
   144  	opts := signers.VerifyOpts{
   145  		NoChain:   argNoChain,
   146  		NoDigests: argNoIntegrityCheck,
   147  		Content:   argContent,
   148  	}
   149  	trusted, err := certloader.LoadAnyCerts(argTrustedCerts)
   150  	if err != nil {
   151  		return opts, err
   152  	}
   153  	opts.TrustedX509 = trusted.X509Certs
   154  	opts.TrustedPgp = trusted.PGPCerts
   155  	if len(opts.TrustedX509) > 0 {
   156  		if argAlsoSystem {
   157  			var err error
   158  			opts.TrustedPool, err = x509.SystemCertPool()
   159  			if err != nil {
   160  				return opts, err
   161  			}
   162  		} else {
   163  			opts.TrustedPool = x509.NewCertPool()
   164  		}
   165  		for _, cert := range opts.TrustedX509 {
   166  			opts.TrustedPool.AddCert(cert)
   167  		}
   168  	}
   169  	return opts, nil
   170  }
   171  

View as plain text