...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package signers
18
19 import (
20 "crypto"
21 "errors"
22 "fmt"
23 "io"
24 "os"
25 "time"
26
27 "github.com/spf13/pflag"
28
29 "github.com/sassoftware/relic/lib/audit"
30 "github.com/sassoftware/relic/lib/certloader"
31 "github.com/sassoftware/relic/lib/magic"
32 "github.com/sassoftware/relic/lib/pgptools"
33 "github.com/sassoftware/relic/lib/pkcs9"
34 "github.com/sassoftware/relic/lib/x509tools"
35 "github.com/sassoftware/relic/signers/sigerrors"
36 "golang.org/x/crypto/openpgp"
37 )
38
39 type Signer struct {
40 Name string
41 Aliases []string
42 Magic magic.FileType
43 CertTypes CertType
44 AllowStdin bool
45
46 TestPath func(string) bool
47
48 FormatLog func(*audit.Info) string
49
50
51 Verify func(*os.File, VerifyOpts) ([]*Signature, error)
52
53 VerifyStream func(io.Reader, VerifyOpts) ([]*Signature, error)
54
55 Transform func(*os.File, SignOpts) (Transformer, error)
56
57 Sign func(io.Reader, *certloader.Certificate, SignOpts) ([]byte, error)
58
59 Fixup func(*os.File) error
60
61 flags *pflag.FlagSet
62 }
63
64 type CertType uint
65
66 const (
67 CertTypeX509 CertType = 1 << iota
68 CertTypePgp
69 )
70
71 type Signature struct {
72 Package string
73 SigInfo string
74 CreationTime time.Time
75 Hash crypto.Hash
76 Signer string
77 SignerPgp *openpgp.Entity
78 X509Signature *pkcs9.TimestampedSignature
79 }
80
81 func (s *Signature) SignerName() string {
82 if s.Signer != "" {
83 return s.Signer
84 }
85 if s.X509Signature != nil {
86 return fmt.Sprintf("`%s`", x509tools.FormatSubject(s.X509Signature.Certificate))
87 }
88 if s.SignerPgp != nil {
89 return fmt.Sprintf("`%s`(%x)", pgptools.EntityName(s.SignerPgp), s.SignerPgp.PrimaryKey.KeyId)
90 }
91 return "UNKNOWN"
92 }
93
94 var registered []*Signer
95 var flagMap map[string][]string
96
97 func Register(s *Signer) {
98 registered = append(registered, s)
99 }
100
101
102 func ByName(name string) *Signer {
103 for _, s := range registered {
104 if s.Name == name {
105 return s
106 }
107 for _, n2 := range s.Aliases {
108 if n2 == name {
109 return s
110 }
111 }
112 }
113 return nil
114 }
115
116
117 func ByMagic(m magic.FileType) *Signer {
118 if m == magic.FileTypeUnknown {
119 return nil
120 }
121 for _, s := range registered {
122 if s.Magic == m {
123 return s
124 }
125 }
126 return nil
127 }
128
129
130 func ByFileName(name string) *Signer {
131 for _, s := range registered {
132 if s.TestPath != nil && s.TestPath(name) {
133 return s
134 }
135 }
136 return nil
137 }
138
139
140
141 func ByFile(name, sigtype string) (*Signer, error) {
142 if sigtype != "" {
143 mod := ByName(sigtype)
144 if mod == nil {
145 return nil, errors.New("no signer with that name")
146 }
147 return mod, nil
148 }
149 if name == "-" {
150 return nil, errors.New("reading from standard input is not supported")
151 }
152 f, err := os.Open(name)
153 if err != nil {
154 return nil, err
155 }
156 defer f.Close()
157 fileType, compressionType := magic.DetectCompressed(f)
158 if compressionType != magic.CompressedNone {
159 return nil, errors.New("cannot sign compressed file")
160 }
161 if mod := ByMagic(fileType); mod != nil {
162 return mod, nil
163 } else if mod := ByFileName(name); mod != nil {
164 return mod, nil
165 }
166 return nil, errors.New("unknown filetype")
167 }
168
169
170
171
172 func (s *Signer) Flags() *pflag.FlagSet {
173 if s.flags == nil {
174 s.flags = pflag.NewFlagSet(s.Name, pflag.ExitOnError)
175 }
176 return s.flags
177 }
178
179
180 func MergeFlags(fs *pflag.FlagSet) {
181 if flagMap == nil {
182 flagMap = make(map[string][]string)
183 }
184 for _, s := range registered {
185 if s.flags == nil {
186 continue
187 }
188 fs.AddFlagSet(s.flags)
189 s.flags.VisitAll(func(flag *pflag.Flag) {
190 flagMap[flag.Name] = append(flagMap[flag.Name], s.Name)
191 })
192 }
193 }
194
195
196 func (s *Signer) IsSigned(f *os.File) (bool, error) {
197 var err error
198 if s.VerifyStream != nil {
199 _, err = s.VerifyStream(f, VerifyOpts{NoDigests: true, NoChain: true})
200 } else if s.Verify != nil {
201 _, err = s.Verify(f, VerifyOpts{NoDigests: true, NoChain: true})
202 } else {
203 return false, errors.New("cannot check if this type of file is signed")
204 }
205 if err == nil {
206 return true, nil
207 }
208 switch err.(type) {
209 case sigerrors.NotSignedError:
210 return false, nil
211 case pgptools.ErrNoKey:
212 return true, nil
213 }
214 return false, err
215 }
216
View as plain text