// Copyright (c) The OpenTofu Authors // SPDX-License-Identifier: MPL-2.0 // Copyright (c) 2023 HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package getproviders import ( "bytes" "testing" "github.com/ProtonMail/go-crypto/openpgp" "github.com/ProtonMail/go-crypto/openpgp/armor" ) // This file contains only some helper functions for the tests in package_authentication_test.go. // There are not actually any tests in here. // // We use these helpers sparingly to minimize the number of opaque-to-humans artifacts // we need to include as hard-coded constants, instead deriving the opaque artifacts from // more human-accessible artifacts where possible. However, we must be careful to make sure // that our use of these helpers does not cause a test to effectively "cheat" by creating // a situation that could not possibly occur in realistic use. // pgpTestEntity returns a freshly-generated [openpgp.Entity] with the given name and // a hard-coded comment and fake email address. The private key is generated randomly // on request. // // We generate keys on the fly, rather than hard-coding them, to avoid dealiing with the // noise generated by zealous security scanners that get (justifyably) nervous when // they find a private key included directly in the source code of a codebase. However, // this just-in-time generation does unfortunately come at a small performance cost, // so tests should avoid calling this from inside a loop. func pgpTestEntity(t *testing.T, name string) *openpgp.Entity { t.Helper() entity, err := openpgp.NewEntity(name, "throwaway key used only for testing", "testing@invalid", nil) if err != nil { t.Fatalf("failed to generate a PGP key for testing: %s", err) } return entity } // pgpPublicKeyForTestEntity returns an "armored" representation of the public key // of the given entity, as we'd expect to obtain from an OpenTofu provider // registry when performing GPG verification of a provider release, and // a hex representation of the key's ID that we'd use to report the use of // the key in a successful authentication result. func pgpPublicKeyForTestEntity(t *testing.T, entity *openpgp.Entity) ([]byte, string) { // The "armored" representation, described in RFC 4880 chapter 6, // is a PEM-like ASCII-only representation of key data. Therefore // we have two layers to deal with here: the armor encoding, and // the inner raw representation of the public key. var buf bytes.Buffer w, err := armor.Encode(&buf, "PGP PUBLIC KEY BLOCK", nil) if err != nil { t.Fatalf("failed to begin ASCII-armored public key block: %s", err) } err = entity.Serialize(w) if err != nil { t.Fatalf("failed to serialize the public key part of the PGP entity: %s", err) } err = w.Close() if err != nil { t.Fatalf("failed to add ASCII-armor footer: %s", err) } return buf.Bytes(), entity.PrimaryKey.KeyIdString() } // pgpSignForTesting generates a signature for the given message using the private // key from the given signer, in the raw binary format we'd normally expect to // receive from an artifact linked in an OpenTofu provider registry. func pgpSignForTesting(t *testing.T, message []byte, signer *openpgp.Entity) []byte { t.Helper() var buf bytes.Buffer err := openpgp.DetachSign(&buf, signer, bytes.NewReader(message), nil) if err != nil { t.Fatalf("failed to PGP sign message for testing: %s", err) } return buf.Bytes() }