Skip to content

Commit

Permalink
Authenticate releases using the embedded verification key.
Browse files Browse the repository at this point in the history
Fixes bazelbuild#15.

Signed-off-by: Piotr Sikora <[email protected]>
  • Loading branch information
PiotrSikora committed Oct 29, 2020
1 parent 3b5aa44 commit 453ab29
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 6 deletions.
2 changes: 1 addition & 1 deletion core/repositories.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ func (r *Repositories) DownloadFromBaseURL(baseURL, version, destDir, destFile s
}

url := fmt.Sprintf("%s/%s/%s", baseURL, version, srcFile)
return httputil.DownloadBinary(url, destDir, destFile)
return httputil.DownloadBinary(url, "", "", destDir, destFile)
}

// 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.
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ require (
github.com/bazelbuild/rules_go v0.24.3
github.com/hashicorp/go-version v1.2.1
github.com/mitchellh/go-homedir v1.1.0
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897
)
7 changes: 7 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,10 @@ github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pB
github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 h1:pLI5jrR7OSLijeIDcmRxNmw2api+jEfxLoykJVice/E=
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
36 changes: 35 additions & 1 deletion httputil/httputil.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ package httputil

import (
"fmt"
"golang.org/x/crypto/openpgp"
"io"
"io/ioutil"
"log"
"net/http"
"os"
"path/filepath"
"strings"
"time"
)

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

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

if (signatureURL != "" && verificationKey != "") {
tmpfile.Seek(0, io.SeekStart)

signature, err := getClient().Get(signatureURL)
if err != nil {
return "", fmt.Errorf("HTTP GET %s failed: %v", signatureURL, err)
}
defer signature.Body.Close()

if signature.StatusCode != 200 {
return "", fmt.Errorf("HTTP GET %s failed with error %v", signatureURL, signature.StatusCode)
}

keys, err := openpgp.ReadArmoredKeyRing(strings.NewReader(verificationKey))
if err != nil {
return "", fmt.Errorf("failed to load the embedded Verification Key")
}

if len(keys) != 1 {
return "", fmt.Errorf("failed to load the embedded Verification Key")
}

entity, err := openpgp.CheckDetachedSignature(keys, tmpfile, signature.Body)
if err != nil {
return "", fmt.Errorf("failed to verify the downloaded file with signature %s", signatureURL)
}

for _, identity := range entity.Identities {
log.Printf("Signed by %s", identity.Name)
}
}

tmpfile.Close()
err = os.Rename(tmpfile.Name(), destinationPath)
if err != nil {
Expand Down
59 changes: 56 additions & 3 deletions repositories/gcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,59 @@ const (
candidateBaseURL = "https://releases.bazel.build"
nonCandidateBaseURL = "https://storage.googleapis.com/bazel-builds/artifacts"
lastGreenBaseURL = "https://storage.googleapis.com/bazel-untrusted-builds/last_green_commit/"
verificationKey =
`-----BEGIN PGP PUBLIC KEY BLOCK-----
mQINBFdEmzkBEACzj8tMYUau9oFZWNDytcQWazEO6LrTTtdQ98d3JcnVyrpT16yg
I/QfGXA8LuDdKYpUDNjehLtBL3IZp4xe375Jh8v2IA2iQ5RXGN+lgKJ6rNwm15Kr
qYeCZlU9uQVpZuhKLXsWK6PleyQHjslNUN/HtykIlmMz4Nnl3orT7lMI5rsGCmk0
1Kth0DFh8SD9Vn2G4huddwxM8/tYj1QmWPCTgybATNuZ0L60INH8v6+J2jJzViVc
NRnR7mpouGmRy/rcr6eY9QieOwDou116TrVRFfcBRhocCI5b6uCRuhaqZ6Qs28Bx
4t5JVksXJ7fJoTy2B2s/rPx/8j4MDVEdU8b686ZDHbKYjaYBYEfBqePXScp8ndul
XWwS2lcedPihOUl6oQQYy59inWIpxi0agm0MXJAF1Bc3ToSQdHw/p0Y21kYxE2pg
EaUeElVccec5poAaHSPprUeej9bD9oIC4sMCsLs7eCQx2iP+cR7CItz6GQtuZrvS
PnKju1SKl5iwzfDQGpi6u6UAMFmc53EaH05naYDAigCueZ+/2rIaY358bECK6/VR
kyrBqpeq6VkWUeOkt03VqoPzrw4gEzRvfRtLj+D2j/pZCH3vyMYHzbaaXBv6AT0e
RmgtGo9I9BYqKSWlGEF0D+CQ3uZfOyovvrbYqNaHynFBtrx/ZkM82gMA5QARAQAB
tEdCYXplbCBEZXZlbG9wZXIgKEJhemVsIEFQVCByZXBvc2l0b3J5IGtleSkgPGJh
emVsLWRldkBnb29nbGVncm91cHMuY29tPokCVQQTAQgAPwIbAwYLCQgHAwIGFQgC
CQoLBBYCAwECHgECF4AWIQRxodDvz+tigf0EN8k9WRm0SEV+4AUCXsoWGgUJC0fh
4QAKCRA9WRm0SEV+4NDCD/9c5rhZREBlikdi5QYRq1YOkwzJLXFoVe0FonEwMuWK
fQzT/rIwyh14tssptU5+eXwTEXL0ZDskgzvrFSpzjQZzcSG/gzNCATNfrZpC2nfE
SxMKOeIwQedn26YIHCI8s9tEQ7BSvfBfJgqfIo3IURhmfzNMj+qszca+3IDYAlAy
8lxUVbJcIQ0apnAdnIadtydzca56mMN7ma+btddaWLpAdyfUvQ/Zsx3TYYLF7inQ
km0JpzISN0fGngzGNDGNmtHNhCdSpyfkr+7fvpbKAYkSH7uZ1AIPDyHdLIwDQnX2
kbLRkxKncKGSDhUSdlJTl0x36cU+xmgO15FFdOyk3BUfrlfDrgXIBjeX8KNh9TV6
HgFFR/mNONoJ93ZvZQNO2s1gbPZJe3VJ1Q5PMLW1sdl8q8JthBwT/5TJ1k8E5VYj
jAc8dl+RAALxqj+eo5xI45o1FdV5s1aGDjbwFoCIhGCy2zaog1q5wnhmEptAAD0S
TVbJSpwNiLlPIcGVaCjXp8Ow3SzOGTRKIjFTO/I6FiSJOpgfri07clXmnb4ETjou
mUdglg8/8nQ120zHEOqoSzzIbTNUDjNZY8SuY6Ig3/ObQ/JAFS0i6h74KLfXUZzn
uETY7KURLdyPAhL37Hb9FDhvkJCUO/l6eqDh9jk1JjB7Cvb7hEvnbvDrr2hWNAL7
RrkCDQRXRJs5ARAA55/1VBlDpV/ElUyLmRyPCz/V+msHdinyw4Mv5DJQupuZwlMy
vxPPzc7GmsIfk1zuOzDWirNs22r43ak6dsAvpcU+iVBi46MqUcbNtC+kfxlKiToD
PCs82rdfCgHT7XYDzrCWlqNQ9++BqM2OYRIxyEucizeofWPlrJUgKvu8fWLVZ6bY
n4L/PqAhobhuSjRcoB5Tp81hGa4cscKIGIqhymfnguaY8viJ83tHPUqQJoApNPy8
q1pWHSDV6zBv71beqV2b6cBzp7VqNYOIuqE6ZNBFWuCG3zRc9ia2/bHxx2TGAQJt
PpPzitm0xkB3GGN06YnnSCE+f2j+7F0IO6uFlSy7ho0PoSFbDgR91kJK3S0ZBZx4
H21cIpWWBzf9Nd1M4H3O7KhnGSZDq6+tXZ9/F/ZUvCZHpQlJewDPY9315Ymacf5C
Zk8xeE5UUIxFMdOxF8B7Itb6rbFWv+tzWdX/0/M8/b0ZJhVvngWzuh/agdS4E5an
f7ahGWM96jPRIQEb9DRN2YGp9hOiX2sZqkhxE5zWqD2gdXp2ZAxMCTHf4ijzOVsO
nde7b5BqC0JL73gNwf1iOHyCAzqGiFfah8/odBTDhMsdVMsjSIxzcwlwRnzy+hBs
dYpP19ieJCMoERJTbUgSspPdhY/Y4ChzlFHjiAKYT6vXiYcKS04stCtHqwEAEQEA
AYkCPAQYAQgAJgIbDBYhBHGh0O/P62KB/QQ3yT1ZGbRIRX7gBQJeyhYlBQkLR+Hs
AAoJED1ZGbRIRX7g3Y8P/iuOAHmyCMeSELvUs9ZvLYJKGzmz67R8fJSmgst/Bs3p
dWCAjGE56M6UgZzHXK+fBRWFPDOXT64XNq0UIG7tThthwe4Gdvg/5rWG61Pe/vCZ
2FkMAlEMkuufZYMcw9jItHMKLcYyW/jtN9EzCX+vM6SZlu4o8la5rCIBEaiKfzft
a/dRMjW+RqQnU31NQCDAy3zoGUCQumJtv3GVbMYHIrRZua2yyNo9Iborh2SVdBbK
v9WJKH4JcCHd0/XDGdys6EXeATIIRxchumkmxpIg87OhsC0n5yuH1FnFIFQEjbYX
bb46F7ZFT+8Tov+lgMEw4CZmps4uvvZlKbIH4Zi/ULiobwvm2ad3nejWICmGmHYz
ro6t08hdcY6GnOzCpDwx9yHechMCkU3KEE98nb/CxcmA4VzDHudTJe7o0OyaSarh
6D5WcXf7D9FfcKmUD9xaCsfXh66OCksMVGE1JctrO1wQTF2jTdTUq7mmi30tlM+o
JjVk65OSOd4JYol8auzE4oXOfsNzXbyvj7WzM1v5m7C45jOL+Ly7I3IUzZNfF41J
AMmSd73EOoR9YH4qTrL3jx69Ekf7ww70Qea5enLE8xUgQfGTOaEHxkFcEovmzv54
6IVe083iK8alXD/9OUTaDY9NwMnOn1K1aU2XOfliGGLgwwaHg+wVFh5rZIHsDl7v
=Embu
-----END PGP PUBLIC KEY BLOCK-----`
)

var (
Expand Down Expand Up @@ -106,7 +159,7 @@ func (gcs *GCSRepo) DownloadRelease(version, destDir, destFile string) (string,
}

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

func (gcs *GCSRepo) removeCandidates(history []string, lastN int) ([]string, error) {
Expand Down Expand Up @@ -189,7 +242,7 @@ func (gcs *GCSRepo) DownloadCandidate(version, destDir, destFile string) (string
baseVersion := versionComponents[0]
rcVersion := "rc" + versionComponents[1]
url := fmt.Sprintf("%s/%s/%s/%s", candidateBaseURL, baseVersion, rcVersion, srcFile)
return httputil.DownloadBinary(url, destDir, destFile)
return httputil.DownloadBinary(url, url + ".sig", verificationKey, destDir, destFile)
}

// CommitRepo
Expand All @@ -210,5 +263,5 @@ func (gcs *GCSRepo) GetLastGreenCommit(bazeliskHome string, downstreamGreen bool
func (gcs *GCSRepo) DownloadAtCommit(commit, destDir, destFile string) (string, error) {
log.Printf("Using unreleased version at commit %s", commit)
url := fmt.Sprintf("%s/%s/%s/bazel", nonCandidateBaseURL, platforms.GetPlatform(), commit)
return httputil.DownloadBinary(url, destDir, destFile)
return httputil.DownloadBinary(url, "", "", destDir, destFile)
}
2 changes: 1 addition & 1 deletion repositories/github.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,5 +59,5 @@ func (gh *GitHubRepo) DownloadVersion(fork, version, destDir, destFile string) (
return "", err
}
url := fmt.Sprintf(urlPattern, fork, version, filename)
return httputil.DownloadBinary(url, destDir, destFile)
return httputil.DownloadBinary(url, "", "", destDir, destFile)
}

0 comments on commit 453ab29

Please sign in to comment.