Skip to content

Commit 6ed0581

Browse files
committed
Authenticate releases using the embedded verification key.
Fixes #15. Signed-off-by: Piotr Sikora <[email protected]>
1 parent 3b5aa44 commit 6ed0581

File tree

6 files changed

+102
-6
lines changed

6 files changed

+102
-6
lines changed

core/repositories.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ func (r *Repositories) DownloadFromBaseURL(baseURL, version, destDir, destFile s
175175
}
176176

177177
url := fmt.Sprintf("%s/%s/%s", baseURL, version, srcFile)
178-
return httputil.DownloadBinary(url, destDir, destFile)
178+
return httputil.DownloadBinary(url, "", "", destDir, destFile)
179179
}
180180

181181
// CreateRepositories creates a new Repositories instance with the given repositories. Any nil repository will be replaced by a dummy repository that raises an error whenever a download is attempted.

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ require (
66
github.com/bazelbuild/rules_go v0.24.3
77
github.com/hashicorp/go-version v1.2.1
88
github.com/mitchellh/go-homedir v1.1.0
9+
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897
910
)

go.sum

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,10 @@ github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pB
44
github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
55
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
66
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
7+
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
8+
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 h1:pLI5jrR7OSLijeIDcmRxNmw2api+jEfxLoykJVice/E=
9+
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
10+
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
11+
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
12+
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
13+
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

httputil/httputil.go

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@ package httputil
33

44
import (
55
"fmt"
6+
"golang.org/x/crypto/openpgp"
67
"io"
78
"io/ioutil"
89
"log"
910
"net/http"
1011
"os"
1112
"path/filepath"
13+
"strings"
1214
"time"
1315
)
1416

@@ -51,7 +53,7 @@ func ReadRemoteFile(url string, token string) ([]byte, error) {
5153
}
5254

5355
// DownloadBinary downloads a file from the given URL into the specified location, marks it executable and returns its full path.
54-
func DownloadBinary(originURL, destDir, destFile string) (string, error) {
56+
func DownloadBinary(originURL, signatureURL, verificationKey, destDir, destFile string) (string, error) {
5557
err := os.MkdirAll(destDir, 0755)
5658
if err != nil {
5759
return "", fmt.Errorf("could not create directory %s: %v", destDir, err)
@@ -91,6 +93,38 @@ func DownloadBinary(originURL, destDir, destFile string) (string, error) {
9193
return "", fmt.Errorf("could not chmod file %s: %v", tmpfile.Name(), err)
9294
}
9395

96+
if signatureURL != "" && verificationKey != "" {
97+
tmpfile.Seek(0, io.SeekStart)
98+
99+
signature, err := getClient().Get(signatureURL)
100+
if err != nil {
101+
return "", fmt.Errorf("HTTP GET %s failed: %v", signatureURL, err)
102+
}
103+
defer signature.Body.Close()
104+
105+
if signature.StatusCode != 200 {
106+
return "", fmt.Errorf("HTTP GET %s failed with error %v", signatureURL, signature.StatusCode)
107+
}
108+
109+
keys, err := openpgp.ReadArmoredKeyRing(strings.NewReader(verificationKey))
110+
if err != nil {
111+
return "", fmt.Errorf("failed to load the embedded Verification Key")
112+
}
113+
114+
if len(keys) != 1 {
115+
return "", fmt.Errorf("failed to load the embedded Verification Key")
116+
}
117+
118+
entity, err := openpgp.CheckDetachedSignature(keys, tmpfile, signature.Body)
119+
if err != nil {
120+
return "", fmt.Errorf("failed to verify the downloaded file using signature from %s", signatureURL)
121+
}
122+
123+
for _, identity := range entity.Identities {
124+
log.Printf("Signed by %s", identity.Name)
125+
}
126+
}
127+
94128
tmpfile.Close()
95129
err = os.Rename(tmpfile.Name(), destinationPath)
96130
if err != nil {

repositories/gcs.go

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,60 @@ const (
1919
candidateBaseURL = "https://releases.bazel.build"
2020
nonCandidateBaseURL = "https://storage.googleapis.com/bazel-builds/artifacts"
2121
lastGreenBaseURL = "https://storage.googleapis.com/bazel-untrusted-builds/last_green_commit/"
22+
verificationKey = `
23+
-----BEGIN PGP PUBLIC KEY BLOCK-----
24+
25+
mQINBFdEmzkBEACzj8tMYUau9oFZWNDytcQWazEO6LrTTtdQ98d3JcnVyrpT16yg
26+
I/QfGXA8LuDdKYpUDNjehLtBL3IZp4xe375Jh8v2IA2iQ5RXGN+lgKJ6rNwm15Kr
27+
qYeCZlU9uQVpZuhKLXsWK6PleyQHjslNUN/HtykIlmMz4Nnl3orT7lMI5rsGCmk0
28+
1Kth0DFh8SD9Vn2G4huddwxM8/tYj1QmWPCTgybATNuZ0L60INH8v6+J2jJzViVc
29+
NRnR7mpouGmRy/rcr6eY9QieOwDou116TrVRFfcBRhocCI5b6uCRuhaqZ6Qs28Bx
30+
4t5JVksXJ7fJoTy2B2s/rPx/8j4MDVEdU8b686ZDHbKYjaYBYEfBqePXScp8ndul
31+
XWwS2lcedPihOUl6oQQYy59inWIpxi0agm0MXJAF1Bc3ToSQdHw/p0Y21kYxE2pg
32+
EaUeElVccec5poAaHSPprUeej9bD9oIC4sMCsLs7eCQx2iP+cR7CItz6GQtuZrvS
33+
PnKju1SKl5iwzfDQGpi6u6UAMFmc53EaH05naYDAigCueZ+/2rIaY358bECK6/VR
34+
kyrBqpeq6VkWUeOkt03VqoPzrw4gEzRvfRtLj+D2j/pZCH3vyMYHzbaaXBv6AT0e
35+
RmgtGo9I9BYqKSWlGEF0D+CQ3uZfOyovvrbYqNaHynFBtrx/ZkM82gMA5QARAQAB
36+
tEdCYXplbCBEZXZlbG9wZXIgKEJhemVsIEFQVCByZXBvc2l0b3J5IGtleSkgPGJh
37+
emVsLWRldkBnb29nbGVncm91cHMuY29tPokCVQQTAQgAPwIbAwYLCQgHAwIGFQgC
38+
CQoLBBYCAwECHgECF4AWIQRxodDvz+tigf0EN8k9WRm0SEV+4AUCXsoWGgUJC0fh
39+
4QAKCRA9WRm0SEV+4NDCD/9c5rhZREBlikdi5QYRq1YOkwzJLXFoVe0FonEwMuWK
40+
fQzT/rIwyh14tssptU5+eXwTEXL0ZDskgzvrFSpzjQZzcSG/gzNCATNfrZpC2nfE
41+
SxMKOeIwQedn26YIHCI8s9tEQ7BSvfBfJgqfIo3IURhmfzNMj+qszca+3IDYAlAy
42+
8lxUVbJcIQ0apnAdnIadtydzca56mMN7ma+btddaWLpAdyfUvQ/Zsx3TYYLF7inQ
43+
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
73+
=Embu
74+
-----END PGP PUBLIC KEY BLOCK-----
75+
`
2276
)
2377

2478
var (
@@ -106,7 +160,7 @@ func (gcs *GCSRepo) DownloadRelease(version, destDir, destFile string) (string,
106160
}
107161

108162
url := fmt.Sprintf("%s/%s/release/%s", candidateBaseURL, version, srcFile)
109-
return httputil.DownloadBinary(url, destDir, destFile)
163+
return httputil.DownloadBinary(url, url+".sig", verificationKey, destDir, destFile)
110164
}
111165

112166
func (gcs *GCSRepo) removeCandidates(history []string, lastN int) ([]string, error) {
@@ -189,7 +243,7 @@ func (gcs *GCSRepo) DownloadCandidate(version, destDir, destFile string) (string
189243
baseVersion := versionComponents[0]
190244
rcVersion := "rc" + versionComponents[1]
191245
url := fmt.Sprintf("%s/%s/%s/%s", candidateBaseURL, baseVersion, rcVersion, srcFile)
192-
return httputil.DownloadBinary(url, destDir, destFile)
246+
return httputil.DownloadBinary(url, url+".sig", verificationKey, destDir, destFile)
193247
}
194248

195249
// CommitRepo
@@ -210,5 +264,5 @@ func (gcs *GCSRepo) GetLastGreenCommit(bazeliskHome string, downstreamGreen bool
210264
func (gcs *GCSRepo) DownloadAtCommit(commit, destDir, destFile string) (string, error) {
211265
log.Printf("Using unreleased version at commit %s", commit)
212266
url := fmt.Sprintf("%s/%s/%s/bazel", nonCandidateBaseURL, platforms.GetPlatform(), commit)
213-
return httputil.DownloadBinary(url, destDir, destFile)
267+
return httputil.DownloadBinary(url, "", "", destDir, destFile)
214268
}

repositories/github.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,5 +59,5 @@ func (gh *GitHubRepo) DownloadVersion(fork, version, destDir, destFile string) (
5959
return "", err
6060
}
6161
url := fmt.Sprintf(urlPattern, fork, version, filename)
62-
return httputil.DownloadBinary(url, destDir, destFile)
62+
return httputil.DownloadBinary(url, "", "", destDir, destFile)
6363
}

0 commit comments

Comments
 (0)