1
2
3
4
5
6
7
8
9
10
11
12
13
14
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