plugin/discovery: verify checksum matches Registry response
This commit is contained in:
parent
2632ccc5d3
commit
1a32617d5e
|
@ -36,6 +36,12 @@ files using the keys downloaded from the Terraform Registry. This may mean that
|
|||
the publisher of the provider removed the key it was signed with, or that the
|
||||
distributed files were changed after this version was released.`
|
||||
|
||||
const checksumVerificationError = `Checksum verification error:
|
||||
The checksum for provider distribution %q from the Terraform Registry
|
||||
did not match the source (%s).
|
||||
This may mean that the distributed files were changed after this version
|
||||
was released.`
|
||||
|
||||
var httpClient *http.Client
|
||||
|
||||
var errVersionNotFound = errors.New("version not found")
|
||||
|
@ -391,21 +397,21 @@ func (i *ProviderInstaller) PurgeUnused(used map[string]PluginMeta) (PluginMetaS
|
|||
return removed, errs
|
||||
}
|
||||
|
||||
func (i *ProviderInstaller) getProviderChecksum(urls *response.TerraformProviderPlatformLocation) (string, error) {
|
||||
func (i *ProviderInstaller) getProviderChecksum(resp *response.TerraformProviderPlatformLocation) (string, error) {
|
||||
// Get SHA256SUMS file.
|
||||
shasums, err := getFile(urls.ShasumsURL)
|
||||
shasums, err := getFile(resp.ShasumsURL)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error fetching checksums: %s", err)
|
||||
}
|
||||
|
||||
// Get SHA256SUMS.sig file.
|
||||
signature, err := getFile(urls.ShasumsSignatureURL)
|
||||
signature, err := getFile(resp.ShasumsSignatureURL)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error fetching checksums signature: %s", err)
|
||||
}
|
||||
|
||||
// Verify the GPG signature returned from the Registry.
|
||||
asciiArmor := urls.SigningKeys.GPGASCIIArmor()
|
||||
asciiArmor := resp.SigningKeys.GPGASCIIArmor()
|
||||
signer, err := verifySig(shasums, signature, asciiArmor)
|
||||
if err != nil {
|
||||
log.Printf("[ERROR] error verifying signature: %s", err)
|
||||
|
@ -430,8 +436,13 @@ func (i *ProviderInstaller) getProviderChecksum(urls *response.TerraformProvider
|
|||
identity := strings.Join(identities, ", ")
|
||||
log.Printf("[DEBUG] verified GPG signature with key from %s", identity)
|
||||
|
||||
// Extract checksum for this os/arch platform binary.
|
||||
return checksumForFile(shasums, urls.Filename), nil
|
||||
// Extract checksum for this os/arch platform binary and verify against Registry
|
||||
checksum := checksumForFile(shasums, resp.Filename)
|
||||
if checksum == "" || checksum != resp.Shasum {
|
||||
return "", fmt.Errorf(checksumVerificationError, resp.Filename, resp.ShasumsURL)
|
||||
}
|
||||
|
||||
return checksum, nil
|
||||
}
|
||||
|
||||
func (i *ProviderInstaller) hostname() (string, error) {
|
||||
|
|
|
@ -606,13 +606,14 @@ func TestProviderChecksum(t *testing.T) {
|
|||
|
||||
tests := []struct {
|
||||
Name string
|
||||
URLs *response.TerraformProviderPlatformLocation
|
||||
Resp *response.TerraformProviderPlatformLocation
|
||||
Err bool
|
||||
}{
|
||||
{
|
||||
"good",
|
||||
&response.TerraformProviderPlatformLocation{
|
||||
Filename: "terraform-provider-template_0.1.0_darwin_amd64.zip",
|
||||
Shasum: "3c3e7df78b1f0161a3f941c271d5501f7b5e5f2c53738e7a371459712f5d4726",
|
||||
ShasumsURL: "http://127.0.0.1:8080/terraform-provider-template/0.1.0/terraform-provider-template_0.1.0_SHA256SUMS",
|
||||
ShasumsSignatureURL: "http://127.0.0.1:8080/terraform-provider-template/0.1.0/terraform-provider-template_0.1.0_SHA256SUMS.sig",
|
||||
SigningKeys: response.SigningKeyList{
|
||||
|
@ -653,12 +654,47 @@ func TestProviderChecksum(t *testing.T) {
|
|||
},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"mismatch checksum",
|
||||
&response.TerraformProviderPlatformLocation{
|
||||
Filename: "terraform-provider-template_0.1.0_darwin_amd64.zip",
|
||||
Shasum: "force mismatch",
|
||||
ShasumsURL: "http://127.0.0.1:8080/terraform-provider-template/0.1.0/terraform-provider-template_0.1.0_SHA256SUMS",
|
||||
ShasumsSignatureURL: "http://127.0.0.1:8080/terraform-provider-template/0.1.0/terraform-provider-template_0.1.0_SHA256SUMS.sig",
|
||||
SigningKeys: response.SigningKeyList{
|
||||
GPGKeys: []*response.GPGKey{
|
||||
&response.GPGKey{
|
||||
ASCIIArmor: string(hashicorpKey),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"missing checksum for file",
|
||||
&response.TerraformProviderPlatformLocation{
|
||||
Filename: "terraform-provider-template_0.1.0_darwin_amd64_missing_checksum.zip",
|
||||
Shasum: "checksum",
|
||||
ShasumsURL: "http://127.0.0.1:8080/terraform-provider-template/0.1.0/terraform-provider-template_0.1.0_SHA256SUMS",
|
||||
ShasumsSignatureURL: "http://127.0.0.1:8080/terraform-provider-template/0.1.0/terraform-provider-template_0.1.0_SHA256SUMS.sig",
|
||||
SigningKeys: response.SigningKeyList{
|
||||
GPGKeys: []*response.GPGKey{
|
||||
&response.GPGKey{
|
||||
ASCIIArmor: string(hashicorpKey),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
i := ProviderInstaller{}
|
||||
|
||||
for _, test := range tests {
|
||||
sha256sum, err := i.getProviderChecksum(test.URLs)
|
||||
t.Run(test.Name, func(t *testing.T) {
|
||||
sha256sum, err := i.getProviderChecksum(test.Resp)
|
||||
if test.Err {
|
||||
if err == nil {
|
||||
t.Fatal("succeeded; want error")
|
||||
|
@ -674,11 +710,12 @@ func TestProviderChecksum(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expected := checksumForFile(sumData, test.URLs.Filename)
|
||||
expected := checksumForFile(sumData, test.Resp.Filename)
|
||||
|
||||
if sha256sum != expected {
|
||||
t.Fatalf("expected: %s\ngot %s\n", sha256sum, expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@ package discovery
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/crypto/openpgp"
|
||||
|
@ -13,7 +12,7 @@ import (
|
|||
func verifySig(data, sig []byte, armor string) (*openpgp.Entity, error) {
|
||||
el, err := openpgp.ReadArmoredKeyRing(strings.NewReader(armor))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return openpgp.CheckDetachedSignature(el, bytes.NewReader(data), bytes.NewReader(sig))
|
||||
|
|
Loading…
Reference in New Issue