forked from arduino/arduino-cli
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathsignatures.go
91 lines (82 loc) · 3.8 KB
/
signatures.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
// This file is part of arduino-cli.
//
// Copyright 2020 ARDUINO SA (http://www.arduino.cc/)
//
// This software is released under the GNU General Public License version 3,
// which covers the main part of arduino-cli.
// The terms of this license can be found at:
// https://www.gnu.org/licenses/gpl-3.0.en.html
//
// You can be released from the requirements of the above licenses by purchasing
// a commercial license. Buying such a license is mandatory if you want to
// modify or otherwise use the software for commercial activities involving the
// Arduino software without disclosing the source code of your own applications.
// To purchase a commercial license, send an email to [email protected].
package security
import (
"bytes"
"embed"
"errors"
"io"
"os"
"github.com/ProtonMail/go-crypto/openpgp"
pgperrors "github.com/ProtonMail/go-crypto/openpgp/errors"
"github.com/arduino/arduino-cli/internal/i18n"
"github.com/arduino/go-paths-helper"
)
//go:embed keys/*
var keys embed.FS
// VerifyArduinoDetachedSignature checks that the detached GPG signature (in the
// signaturePath file) matches the given targetPath file and is an authentic
// signature from the bundled trusted keychain. If any of the above conditions
// fails this function returns false. The PGP entity in the trusted keychain that
// produced the signature is returned too. This function use the default and bundled
// arduino_public.gpg.key
func VerifyArduinoDetachedSignature(targetPath *paths.Path, signaturePath *paths.Path) (bool, *openpgp.Entity, error) {
arduinoKeyringFile, err := keys.Open("keys/arduino_public.gpg.key")
if err != nil {
panic("could not find bundled signature keys")
}
defer arduinoKeyringFile.Close()
return VerifySignature(targetPath, signaturePath, arduinoKeyringFile)
}
// VerifyDetachedSignature checks that the detached GPG signature (in the
// signaturePath file) matches the given targetPath file and is an authentic
// signature from the bundled trusted keychain. The keyPath is the path of the public key used.
// This function allows to specify the path of the key to use.
// If any of the above conditions fails this function returns false.
// The PGP entity in the trusted keychain that produced the signature is returned too.
func VerifyDetachedSignature(targetPath *paths.Path, signaturePath *paths.Path, keyPath *paths.Path) (bool, *openpgp.Entity, error) {
arduinoKeyringFile, err := os.Open(keyPath.String())
if err != nil {
panic("could not open signature keys")
}
defer arduinoKeyringFile.Close()
return VerifySignature(targetPath, signaturePath, arduinoKeyringFile)
}
// VerifySignature checks that the detached GPG signature (in the
// signaturePath file) matches the given targetPath file and is an authentic
// signature. This function allows to pass an io.Reader to read the custom key.
//
// If any of the above conditions fails this function returns false.
//
// The PGP entity in the trusted keychain that produced the signature is returned too.
func VerifySignature(targetPath *paths.Path, signaturePath *paths.Path, arduinoKeyringFile io.Reader) (bool, *openpgp.Entity, error) {
keyRing, err := openpgp.ReadKeyRing(arduinoKeyringFile)
if err != nil {
return false, nil, errors.New(i18n.Tr("retrieving Arduino public keys: %s", err))
}
target, err := targetPath.ReadFile()
if err != nil {
return false, nil, errors.New(i18n.Tr("opening target file: %s", err))
}
signature, err := signaturePath.ReadFile()
if err != nil {
return false, nil, errors.New(i18n.Tr("opening signature file: %s", err))
}
signer, err := openpgp.CheckDetachedSignature(keyRing, bytes.NewBuffer(target), bytes.NewBuffer(signature), nil)
if errors.Is(err, pgperrors.ErrSignatureExpired) {
err = errors.New(i18n.Tr("signature expired: is your system clock set correctly?"))
}
return (signer != nil && err == nil), signer, err
}