1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package pgp
17
18 import (
19 "bufio"
20 "bytes"
21 "context"
22 "crypto/ecdsa"
23 "crypto/ed25519"
24 "crypto/rsa"
25 "encoding/hex"
26 "errors"
27 "fmt"
28 "io"
29 "net/http"
30
31 "github.com/asaskevich/govalidator"
32
33
34 "golang.org/x/crypto/openpgp"
35 "golang.org/x/crypto/openpgp/armor"
36 "golang.org/x/crypto/openpgp/packet"
37
38 "github.com/sigstore/rekor/pkg/pki/identity"
39 "github.com/sigstore/sigstore/pkg/cryptoutils"
40 sigsig "github.com/sigstore/sigstore/pkg/signature"
41 )
42
43
44 type Signature struct {
45 isArmored bool
46 signature []byte
47 }
48
49
50 func NewSignature(r io.Reader) (*Signature, error) {
51 var s Signature
52 var inputBuffer bytes.Buffer
53
54 if _, err := io.Copy(&inputBuffer, r); err != nil {
55 return nil, fmt.Errorf("unable to read PGP signature: %w", err)
56 }
57
58 sigByteReader := bytes.NewReader(inputBuffer.Bytes())
59
60 var sigReader io.Reader
61 sigBlock, err := armor.Decode(sigByteReader)
62 if err == nil {
63 s.isArmored = true
64 if sigBlock.Type != openpgp.SignatureType {
65 return nil, errors.New("invalid PGP signature provided")
66 }
67 sigReader = sigBlock.Body
68 } else {
69 s.isArmored = false
70 if _, err := sigByteReader.Seek(0, io.SeekStart); err != nil {
71 return nil, fmt.Errorf("unable to read binary PGP signature: %w", err)
72 }
73 sigReader = sigByteReader
74 }
75
76 sigPktReader := packet.NewReader(sigReader)
77 sigPkt, err := sigPktReader.Next()
78 if err != nil {
79 return nil, fmt.Errorf("invalid PGP signature: %w", err)
80 }
81
82 if _, ok := sigPkt.(*packet.Signature); !ok {
83 if _, ok := sigPkt.(*packet.SignatureV3); !ok {
84 return nil, errors.New("valid PGP signature was not detected")
85 }
86 }
87
88 s.signature = inputBuffer.Bytes()
89 return &s, nil
90 }
91
92
93 func FetchSignature(ctx context.Context, url string) (*Signature, error) {
94 req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
95 if err != nil {
96 return nil, fmt.Errorf("error initializing fetch for PGP signature: %w", err)
97 }
98 client := &http.Client{}
99 resp, err := client.Do(req)
100 if err != nil {
101 return nil, fmt.Errorf("error fetching PGP signature: %w", err)
102 }
103 defer resp.Body.Close()
104
105 sig, err := NewSignature(resp.Body)
106 if err != nil {
107 return nil, err
108 }
109 return sig, nil
110 }
111
112
113 func (s Signature) CanonicalValue() ([]byte, error) {
114 if len(s.signature) == 0 {
115 return nil, errors.New("PGP signature has not been initialized")
116 }
117
118 if s.isArmored {
119 return s.signature, nil
120 }
121
122 var canonicalBuffer bytes.Buffer
123
124 if err := func() error {
125 ew, err := armor.Encode(&canonicalBuffer, openpgp.SignatureType, nil)
126 if err != nil {
127 return fmt.Errorf("error encoding canonical value of PGP signature: %w", err)
128 }
129 defer ew.Close()
130
131 if _, err := io.Copy(ew, bytes.NewReader(s.signature)); err != nil {
132 return fmt.Errorf("error generating canonical value of PGP signature: %w", err)
133 }
134 return nil
135 }(); err != nil {
136 return nil, err
137 }
138
139 return canonicalBuffer.Bytes(), nil
140 }
141
142
143 func (s Signature) Verify(r io.Reader, k interface{}, _ ...sigsig.VerifyOption) error {
144 if len(s.signature) == 0 {
145 return errors.New("PGP signature has not been initialized")
146 }
147
148 key, ok := k.(*PublicKey)
149 if !ok {
150 return errors.New("cannot use Verify with a non-PGP signature")
151 }
152 if len(key.key) == 0 {
153 return errors.New("PGP public key has not been initialized")
154 }
155
156 verifyFn := openpgp.CheckDetachedSignature
157 if s.isArmored {
158 verifyFn = openpgp.CheckArmoredDetachedSignature
159 }
160
161 if _, err := verifyFn(key.key, r, bytes.NewReader(s.signature)); err != nil {
162 return err
163 }
164
165 return nil
166 }
167
168
169 type PublicKey struct {
170 key openpgp.EntityList
171 }
172
173
174 func NewPublicKey(r io.Reader) (*PublicKey, error) {
175 var k PublicKey
176 var inputBuffer bytes.Buffer
177
178 startToken := []byte(`-----BEGIN PGP`)
179 endToken := []byte(`-----END PGP`)
180
181 bufferedReader := bufio.NewReader(r)
182 armorCheck, err := bufferedReader.Peek(len(startToken))
183 if err != nil {
184 return nil, fmt.Errorf("unable to read PGP public key: %w", err)
185 }
186 if bytes.Equal(startToken, armorCheck) {
187
188 scan := bufio.NewScanner(bufferedReader)
189 scan.Split(bufio.ScanLines)
190
191 for scan.Scan() {
192 line := scan.Bytes()
193 inputBuffer.Write(line)
194 fmt.Fprintf(&inputBuffer, "\n")
195
196 if bytes.HasPrefix(line, endToken) {
197
198 keyBlock, err := armor.Decode(&inputBuffer)
199 if err == nil {
200 if keyBlock.Type != openpgp.PublicKeyType && keyBlock.Type != openpgp.PrivateKeyType {
201 return nil, errors.New("invalid PGP type detected")
202 }
203 keys, err := openpgp.ReadKeyRing(keyBlock.Body)
204 if err != nil {
205 return nil, fmt.Errorf("error reading PGP public key: %w", err)
206 }
207 if k.key == nil {
208 k.key = keys
209 } else {
210 k.key = append(k.key, keys...)
211 }
212 inputBuffer.Reset()
213 } else {
214 return nil, fmt.Errorf("invalid PGP public key provided: %w", err)
215 }
216 }
217 }
218 } else {
219
220 k.key, err = openpgp.ReadKeyRing(bufferedReader)
221 if err != nil {
222 return nil, fmt.Errorf("error reading binary PGP public key: %w", err)
223 }
224 }
225
226 if len(k.key) == len(k.key.DecryptionKeys()) {
227 return nil, errors.New("no PGP public keys could be read")
228 }
229
230 return &k, nil
231 }
232
233
234 func FetchPublicKey(ctx context.Context, url string) (*PublicKey, error) {
235
236 req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
237 if err != nil {
238 return nil, fmt.Errorf("error fetching PGP public key: %w", err)
239 }
240 client := &http.Client{}
241 resp, err := client.Do(req)
242 if err != nil {
243 return nil, fmt.Errorf("error fetching PGP public key: %w", err)
244 }
245 defer resp.Body.Close()
246
247 key, err := NewPublicKey(resp.Body)
248 if err != nil {
249 return nil, err
250 }
251
252 return key, nil
253 }
254
255
256 func (k PublicKey) CanonicalValue() ([]byte, error) {
257 if k.key == nil {
258 return nil, errors.New("PGP public key has not been initialized")
259 }
260
261 var canonicalBuffer bytes.Buffer
262
263
264 if err := func() error {
265 armoredWriter, err := armor.Encode(&canonicalBuffer, openpgp.PublicKeyType, nil)
266 if err != nil {
267 return fmt.Errorf("error generating canonical value of PGP public key: %w", err)
268 }
269 defer armoredWriter.Close()
270
271 for _, entity := range k.key {
272 if err := entity.Serialize(armoredWriter); err != nil {
273 return fmt.Errorf("error generating canonical value of PGP public key: %w", err)
274 }
275 }
276 return nil
277 }(); err != nil {
278 return nil, err
279 }
280
281 return canonicalBuffer.Bytes(), nil
282 }
283
284 func (k PublicKey) KeyRing() (openpgp.KeyRing, error) {
285 if k.key == nil {
286 return nil, errors.New("PGP public key has not been initialized")
287 }
288
289 return k.key, nil
290 }
291
292
293 func (k PublicKey) EmailAddresses() []string {
294 var names []string
295
296 for _, entity := range k.key {
297 for _, identity := range entity.Identities {
298 if govalidator.IsEmail(identity.UserId.Email) {
299 names = append(names, identity.UserId.Email)
300 }
301 }
302 }
303 return names
304 }
305
306
307 func (k PublicKey) Subjects() []string {
308 return k.EmailAddresses()
309 }
310
311
312 func (k PublicKey) Identities() ([]identity.Identity, error) {
313 var ids []identity.Identity
314 for _, entity := range k.key {
315 var keys []*packet.PublicKey
316 keys = append(keys, entity.PrimaryKey)
317 for _, subKey := range entity.Subkeys {
318 keys = append(keys, subKey.PublicKey)
319 }
320 for _, pk := range keys {
321 pubKey := pk.PublicKey
322
323
324
325 switch pubKey.(type) {
326 case *rsa.PublicKey, *ecdsa.PublicKey, ed25519.PublicKey:
327 default:
328 continue
329 }
330 pkixKey, err := cryptoutils.MarshalPublicKeyToDER(pubKey)
331 if err != nil {
332 return nil, err
333 }
334 ids = append(ids, identity.Identity{
335 Crypto: pubKey,
336 Raw: pkixKey,
337 Fingerprint: hex.EncodeToString(pk.Fingerprint[:]),
338 })
339 }
340 }
341 return ids, nil
342 }
343
View as plain text