From a947b6299e09ddf9d03e32411ff8976ad2374bba Mon Sep 17 00:00:00 2001 From: Max Lambrecht Date: Wed, 21 Jun 2023 16:45:26 -0500 Subject: [PATCH 1/3] Improvements in DiskSigner and refactors to use the entire signing certificate chain Signed-off-by: Max Lambrecht --- conf/harvester/harvester_full.conf | 21 +- doc/galadriel_harvester.md | 11 + pkg/common/api/schemas.gen.go | 123 +++--- pkg/common/api/schemas.yaml | 83 ++-- pkg/common/constants/errors.go | 10 + pkg/common/entity/entities.go | 18 +- pkg/common/entity/strings.go | 2 +- pkg/common/x509ca/disk/disk_test.go | 7 +- pkg/harvester/bundlemanager/fedbundles.go | 4 +- pkg/harvester/bundlemanager/spirebundle.go | 17 +- pkg/harvester/catalog/catalog.go | 56 ++- pkg/harvester/catalog/catalog_test.go | 7 +- pkg/harvester/galadrielclient/client.go | 24 +- pkg/harvester/integrity/disk.go | 247 +++++++---- pkg/harvester/integrity/disk_test.go | 403 ++++++++++++------ pkg/server/api/harvester/harvester.gen.go | 208 +++++---- pkg/server/api/harvester/harvester.yaml | 12 +- pkg/server/api/harvester/helper.go | 14 +- pkg/server/api/harvester/helper_test.go | 14 +- pkg/server/catalog/catalog.go | 4 +- pkg/server/catalog/catalog_test.go | 2 +- pkg/server/db/postgres/bundles.sql.go | 50 +-- pkg/server/db/postgres/datastore.go | 22 +- pkg/server/db/postgres/helpers.go | 16 +- .../migrations/1_initialize_schema.up.sql | 16 +- pkg/server/db/postgres/models.gen.go | 16 +- pkg/server/db/postgres/queries/bundles.sql | 4 +- pkg/server/db/sqlite/bundles.sql.go | 52 +-- pkg/server/db/sqlite/datastore.go | 24 +- pkg/server/db/sqlite/helpers.go | 16 +- .../migrations/1_initialize_schema.up.sql | 16 +- pkg/server/db/sqlite/models.gen.go | 16 +- pkg/server/db/sqlite/queries/bundles.sql | 4 +- pkg/server/db/tests/datastore_test.go | 50 +-- pkg/server/endpoints/harvester.go | 2 +- pkg/server/endpoints/harvester_test.go | 30 +- 36 files changed, 926 insertions(+), 695 deletions(-) create mode 100644 pkg/common/constants/errors.go diff --git a/conf/harvester/harvester_full.conf b/conf/harvester/harvester_full.conf index 99557145..b36684f2 100644 --- a/conf/harvester/harvester_full.conf +++ b/conf/harvester/harvester_full.conf @@ -44,8 +44,27 @@ providers { # Enables the signing of bundles using a disk-based key pair. BundleSigner "disk" { - ca_cert_path = "conf/harvester/dummy_root_ca.crt" + # ca_private_key_path: Path to the CA key file. Key files must + # contain a single PEM encoded key. The supported key types are EC + # (ASN.1 or PKCS8 encoded) or RSA (PKCS1 or PKCS8 encoded). ca_private_key_path = "conf/harvester/dummy_root_ca.key" + + # ca_cert_path: If the BundleSigner will use a self-signed CA, cert_file_path + # should specify the path to a single PEM encoded certificate + # representing the CA certificate. If not self-signed, + # ca_cert_path should specify the path to a file that must contain + # one or more certificates necessary to establish a valid certificate + # chain up the root certificates defined in bundle_file_path. + ca_cert_path = "conf/harvester/dummy_root_ca.crt" + + # trust_bundle_path: If Galadriel is using a self-signed CA, bundle_file_path + # can be left unset. If not self-signed, then trust_bundle_path should + # be the path to a file that must contain one or more certificates + # representing the upstream root certificates and the file at + # ca_cert_path contains one or more certificates necessary to chain up + # the root certificates in bundle_file_path (where the first + # certificate in ca_cert_path is the CA certificate). + trust_bundle_path = "" } # BundleVerifier enables the verification of bundle signatures using selected implementations. diff --git a/doc/galadriel_harvester.md b/doc/galadriel_harvester.md index 6f73f385..5d586e75 100644 --- a/doc/galadriel_harvester.md +++ b/doc/galadriel_harvester.md @@ -55,6 +55,17 @@ providers { } ``` +##### BundleSigner - disk + +Configuration details for BundleSigner "disk": + +| Option | Description | +|-----------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `ca_private_key_path` | Path to the CA private key file in PEM format. This path can be relative or absolute. | +| `ca_cert_path` | Path to the CA certificate file in PEM format. If Galadriel is using a self-signed CA, cert_file_path should specify the path to a single PEM encoded certificate representing the CA certificate. If not self-signed, cert_file_path should specify the path to a file that must contain one or more certificates necessary to establish a valid certificate chain up the root certificates defined in bundle_file_path. This path can be relative or absolute. | +| `trust_bundle_path` | Required when the ca_cert_path does not contain a self-signed CA certificate. This is the path to the file containing one or more root CAs. This path can be relative or absolute. | +| `signing_cert_ttl` | The TTL of the signing certificate. This TTL should align with the TTL of the SPIRE bundle. | + #### BundleVerifier This subsection explains the `BundleVerifier` options. diff --git a/pkg/common/api/schemas.gen.go b/pkg/common/api/schemas.gen.go index d69af3b1..abbb9f5b 100644 --- a/pkg/common/api/schemas.gen.go +++ b/pkg/common/api/schemas.gen.go @@ -33,8 +33,8 @@ type ApiError struct { // BundleDigest base64 encoded SHA-256 digest of the bundle type BundleDigest = string -// Certificate X.509 certificate in PEM format -type Certificate = string +// CertificateChain X.509 certificate chain in PEM format +type CertificateChain = string // ConsentStatus defines model for ConsentStatus. type ConsentStatus string @@ -98,69 +98,62 @@ type UUID = openapi_types.UUID // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "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", + "sCcMu7kUFveZl/8KAAD//8GaGKdMGgAA", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/pkg/common/api/schemas.yaml b/pkg/common/api/schemas.yaml index 9375bcc6..f2beb96c 100644 --- a/pkg/common/api/schemas.yaml +++ b/pkg/common/api/schemas.yaml @@ -126,55 +126,48 @@ components: maxLength: 4096 # Number of characters pattern: ^[a-zA-Z0-9\-_]+?\.[a-zA-Z0-9\-_]+?\.([a-zA-Z0-9\-_]+)?$ example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c - Certificate: - description: X.509 certificate in PEM format + CertificateChain: + description: X.509 certificate chain in PEM format type: string format: pem example: |+ -----BEGIN CERTIFICATE----- - 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 + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIIDETCCAfmgAwIBAgIIEmo2RYf4y3UwDQYJKoZIhvcNAQELBQAwEjEQMA4GA1UE + AxMHcm9vdC1jYTAeFw0yMzA2MjAyMDIwMTZaFw0yNDA2MTkyMDIwMTZaMBoxGDAW + BgNVBAMTD2ludGVybWVkaWF0ZS1jYTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC + AQoCggEBAM1bw6CDMJZIQSxUVis8HIF+uCvct9O5cJabHa31DLIk/fPYUoOMgO2w + bGpTC4fmJJa5ztU/Q/hxtlhPIzKILs01qEuVlIaor+NKEPYv13XdJP4hywPq97Ip + Mxku3fx7nOAPAoz6szCy/vXkvhx9z7rP8EW0fPSDYjOwMUEuGdEnpqqTDdgLPCiS + MUsi1FgP4ILgeMDdfpLy/QPapUkKODjPgkYuhnyzrTOV539Aa4B3sXCerTDzVL9f + TUJxleDmAJf429bvjTSWZhCcvtyuYufAJlBIi7ZGB9oGgLop0IIC0u8K1tV2Wh+v + 9G2O1KDiR9MfSOIcP9ISwW7mYYFflGMCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgEG + MA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMjDArZ4p9IMls7XdB6+lOxnShZP + MB8GA1UdIwQYMBaAFCTFpZ9Ruwp4Khnh1YMXwXzKji1vMA0GCSqGSIb3DQEBCwUA + A4IBAQCHoAeLU8yz3ItKx0HPIEEPbG6/4y947IPikxg3kJWLTFKhKP1l32p9MIXm + vJv4GRQuaWOyTlZfenxVH83kq9De9X8kIzs8rRFR5mvPWdCtoSWhIyVKGNZs8sgI + G0GPLjTr8SWq+bubEutI6tfbDBkKjjpLlvV7Saq7b131QA5heJuOKW+sGi433AFQ + ZHm9rlLOWfzc288aFObiHCaOljgWZsYgSXl8P+flbMJF/d3xVAf2Z2REOgOf5l9g + pdgiWFrecNsiMBrDq1jkleAEG/9t4VHGDAtM89NUowOb26UZotKTBZIzoMwZ7orS + 1dO0mLH/NrLvF30nyjgM4iQh7+NO -----END CERTIFICATE----- Signature: type: string diff --git a/pkg/common/constants/errors.go b/pkg/common/constants/errors.go new file mode 100644 index 00000000..0c13077a --- /dev/null +++ b/pkg/common/constants/errors.go @@ -0,0 +1,10 @@ +package constants + +const ( + ErrConfigRequired = "config is required" + ErrCertPathRequired = "certificate file path is required" + ErrPrivateKeyPathRequired = "private key file path is required" + ErrPublicKeyRequired = "public key is required" + ErrTTLRequired = "TTL is required" + ErrTrustBundleRequired = "certificate is not self-signed. A trust bundle is required" +) diff --git a/pkg/common/entity/entities.go b/pkg/common/entity/entities.go index d174c31e..65ee94ef 100644 --- a/pkg/common/entity/entities.go +++ b/pkg/common/entity/entities.go @@ -48,13 +48,13 @@ type JoinToken struct { // Bundle represents a SPIFFE Trust bundle along with its digest. type Bundle struct { - ID uuid.NullUUID - Data []byte // Raw bundle data. - Digest []byte // SHA-256 digest of the bundle data. - Signature []byte // Raw signature of the bundle data. - SigningCertificate []byte - TrustDomainID uuid.UUID - TrustDomainName spiffeid.TrustDomain - CreatedAt time.Time - UpdatedAt time.Time + ID uuid.NullUUID + Data []byte // Raw bundle data. + Digest []byte // SHA-256 digest of the bundle data. + Signature []byte // Raw signature of the bundle data. + SigningCertificateChain []byte + TrustDomainID uuid.UUID + TrustDomainName spiffeid.TrustDomain + CreatedAt time.Time + UpdatedAt time.Time } diff --git a/pkg/common/entity/strings.go b/pkg/common/entity/strings.go index 55d1c41e..a111c0ac 100644 --- a/pkg/common/entity/strings.go +++ b/pkg/common/entity/strings.go @@ -103,7 +103,7 @@ func (b *Bundle) String() string { indent, b.Data, indent, b.Digest, indent, b.Signature, - indent, b.SigningCertificate, + indent, b.SigningCertificateChain, indent, b.TrustDomainID, indent, b.TrustDomainName, indent, b.CreatedAt, diff --git a/pkg/common/x509ca/disk/disk_test.go b/pkg/common/x509ca/disk/disk_test.go index 4050d721..3fdb1b64 100644 --- a/pkg/common/x509ca/disk/disk_test.go +++ b/pkg/common/x509ca/disk/disk_test.go @@ -9,6 +9,7 @@ import ( "testing" "time" + "github.com/HewlettPackard/galadriel/pkg/common/constants" "github.com/HewlettPackard/galadriel/pkg/common/cryptoutil" "github.com/HewlettPackard/galadriel/pkg/common/x509ca" "github.com/HewlettPackard/galadriel/test/certtest" @@ -91,7 +92,7 @@ func TestConfigure(t *testing.T) { KeyFilePath: tempDir + "/intermediate-ca.key", CertFilePath: tempDir + "/intermediate-ca.crt", }, - err: ErrTrustBundleRequired, + err: constants.ErrTrustBundleRequired, }, { name: "NoIntermediateCACert", @@ -99,7 +100,7 @@ func TestConfigure(t *testing.T) { KeyFilePath: tempDir + "/intermediate-ca.key", CertFilePath: "", }, - err: ErrCertPathRequired, + err: constants.ErrCertPathRequired, }, { name: "NoIntermediateCAPrivateKey", @@ -107,7 +108,7 @@ func TestConfigure(t *testing.T) { KeyFilePath: "", CertFilePath: tempDir + "/intermediate-ca.crt", }, - err: ErrPrivateKeyPathRequired, + err: constants.ErrPrivateKeyPathRequired, }, } diff --git a/pkg/harvester/bundlemanager/fedbundles.go b/pkg/harvester/bundlemanager/fedbundles.go index 20214902..3c8bd5fb 100644 --- a/pkg/harvester/bundlemanager/fedbundles.go +++ b/pkg/harvester/bundlemanager/fedbundles.go @@ -169,9 +169,9 @@ func (s *FederatedBundlesSynchronizer) findTrustDomainsToDelete(bundles []*entit // If one of the verifiers can verify the bundle, it returns nil. func (s *FederatedBundlesSynchronizer) validateBundleIntegrity(bundle *entity.Bundle) error { var certChain []*x509.Certificate - if len(bundle.SigningCertificate) > 0 { + if len(bundle.SigningCertificateChain) > 0 { var err error - certChain, err = x509.ParseCertificates(bundle.SigningCertificate) + certChain, err = x509.ParseCertificates(bundle.SigningCertificateChain) if err != nil { return fmt.Errorf("failed to parse signing certificate chain: %w", err) } diff --git a/pkg/harvester/bundlemanager/spirebundle.go b/pkg/harvester/bundlemanager/spirebundle.go index 70fdcabf..8c1d2201 100644 --- a/pkg/harvester/bundlemanager/spirebundle.go +++ b/pkg/harvester/bundlemanager/spirebundle.go @@ -128,20 +128,19 @@ func (s *SpireBundleSynchronizer) prepareBundleForUpload(spireBundle *spiffebund return nil, fmt.Errorf("failed to sign the bundle: %w", err) } - // Check if the signer returned a signing certificate to include in the bundle - var cert []byte - if len(certChain) > 0 { - cert = certChain[0].Raw + var chainBytes []byte + for _, cert := range certChain { + chainBytes = append(chainBytes, cert.Raw...) } digest := cryptoutil.CalculateDigest(bundleBytes) bundle := &entity.Bundle{ - Data: bundleBytes, - Digest: digest[:], - Signature: bundleSignatureBytes, - SigningCertificate: cert, - TrustDomainName: spireBundle.TrustDomain(), + Data: bundleBytes, + Digest: digest[:], + Signature: bundleSignatureBytes, + SigningCertificateChain: chainBytes, + TrustDomainName: spireBundle.TrustDomain(), } return bundle, nil diff --git a/pkg/harvester/catalog/catalog.go b/pkg/harvester/catalog/catalog.go index db2cf1ef..bc606c98 100644 --- a/pkg/harvester/catalog/catalog.go +++ b/pkg/harvester/catalog/catalog.go @@ -6,6 +6,7 @@ import ( "github.com/HewlettPackard/galadriel/pkg/harvester/integrity" "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/gohcl" + "github.com/jmhodges/clock" ) // Catalog is a collection of provider interfaces. @@ -18,6 +19,8 @@ type Catalog interface { type ProvidersRepository struct { bundleSigner integrity.Signer bundleVerifiers []integrity.Verifier + + clock clock.Clock } // ProvidersConfig holds the HCL configuration for the providers. @@ -32,15 +35,6 @@ type providerConfig struct { Options hcl.Body `hcl:",remain"` } -type diskBundleSignerConfig struct { - CACertPath string `hcl:"ca_cert_path"` - CAPrivateKeyPath string `hcl:"ca_private_key_path"` -} - -type diskBundleVerifierConfig struct { - TrustBundlePath string `hcl:"trust_bundle_path"` -} - // New creates a new ProvidersRepository. // It is the responsibility of the caller to load the catalog with providers using LoadFromProvidersConfig. func New() *ProvidersRepository { @@ -71,16 +65,17 @@ func (c *ProvidersRepository) LoadFromProvidersConfig(config *ProvidersConfig) e } var err error - c.bundleSigner, err = loadBundleSigner(config.BundleSigner) + c.bundleSigner, err = loadBundleSigner(config.BundleSigner, c.clock) if err != nil { return fmt.Errorf("error loading BundleSigner: %w", err) } - for _, vc := range config.BundleVerifiers { - bundleVerifier, err := loadBundleVerifier(vc) + for _, bv := range config.BundleVerifiers { + bundleVerifier, err := loadBundleVerifier(bv, c.clock) if err != nil { return fmt.Errorf("error loading BundlerVerifier: %w", err) } + c.bundleVerifiers = append(c.bundleVerifiers, bundleVerifier) } @@ -95,20 +90,20 @@ func (c *ProvidersRepository) GetBundleVerifiers() []integrity.Verifier { return c.bundleVerifiers } -func loadBundleSigner(config *providerConfig) (integrity.Signer, error) { +func loadBundleSigner(config *providerConfig, clk clock.Clock) (integrity.Signer, error) { switch config.Name { case "disk": c, err := decodeDiskBundleSignerConfig(config) if err != nil { return nil, fmt.Errorf("error creating disk bundle verifier: %w", err) } - verifier, err := integrity.NewDiskSigner(&integrity.DiskSignerConfig{ - CACertPath: c.CACertPath, - CAPrivateKeyPath: c.CAPrivateKeyPath, - }) - if err != nil { - return nil, fmt.Errorf("error creating disk bundle signer: %w", err) + c.Clock = clk + + verifier := integrity.NewDiskSigner() + if err := verifier.Configure(c); err != nil { + return nil, fmt.Errorf("error configuring disk bundle verifier: %w", err) } + return verifier, nil case "noop": return integrity.NewNoOpSigner(), nil @@ -117,27 +112,29 @@ func loadBundleSigner(config *providerConfig) (integrity.Signer, error) { return nil, fmt.Errorf("unknown bundle signer provider: %s", config.Name) } -func decodeDiskBundleSignerConfig(config *providerConfig) (*diskBundleSignerConfig, error) { - var dsConfig diskBundleSignerConfig +func decodeDiskBundleSignerConfig(config *providerConfig) (*integrity.DiskSignerConfig, error) { + var dsConfig integrity.DiskSignerConfig if err := gohcl.DecodeBody(config.Options, nil, &dsConfig); err != nil { return nil, err } + return &dsConfig, nil } -func loadBundleVerifier(config *providerConfig) (integrity.Verifier, error) { +func loadBundleVerifier(config *providerConfig, clk clock.Clock) (integrity.Verifier, error) { switch config.Name { case "disk": c, err := decodeDiskBundleVerifierConfig(config) if err != nil { return nil, fmt.Errorf("error creating disk bundle verifier: %w", err) } - verifier, err := integrity.NewDiskVerifier(&integrity.DiskVerifierConfig{ - TrustBundlePath: c.TrustBundlePath, - }) - if err != nil { - return nil, fmt.Errorf("error creating disk bundle verifier: %w", err) + + c.Clock = clk + verifier := integrity.NewDiskVerifier() + if err := verifier.Configure(c); err != nil { + return nil, fmt.Errorf("error configuring disk bundle verifier: %w", err) } + return verifier, nil case "noop": return integrity.NewNoOpVerifier(), nil @@ -146,10 +143,11 @@ func loadBundleVerifier(config *providerConfig) (integrity.Verifier, error) { return nil, fmt.Errorf("unknown bundle signer provider: %s", config.Name) } -func decodeDiskBundleVerifierConfig(config *providerConfig) (*diskBundleVerifierConfig, error) { - var dsConfig diskBundleVerifierConfig +func decodeDiskBundleVerifierConfig(config *providerConfig) (*integrity.DiskVerifierConfig, error) { + var dsConfig integrity.DiskVerifierConfig if err := gohcl.DecodeBody(config.Options, nil, &dsConfig); err != nil { return nil, err } + return &dsConfig, nil } diff --git a/pkg/harvester/catalog/catalog_test.go b/pkg/harvester/catalog/catalog_test.go index 408e0ca5..53e32548 100644 --- a/pkg/harvester/catalog/catalog_test.go +++ b/pkg/harvester/catalog/catalog_test.go @@ -19,11 +19,13 @@ providers { BundleSigner "disk" { ca_cert_path = "%s" ca_private_key_path = "%s" + trust_bundle_path = "%s" + signing_cert_ttl = "%s" } BundleVerifier "disk" { trust_bundle_path = "%s" } -BundleVerifier "noop" { + BundleVerifier "noop" { } } ` @@ -56,7 +58,7 @@ func TestLoadFromProvidersConfig(t *testing.T) { tempDir, cleanup := setupTest(t) defer cleanup() - hclConfig := fmt.Sprintf(hclConfigTemplate, tempDir+"/root-ca.crt", tempDir+"/root-ca.key", tempDir+"/root-ca.crt") + hclConfig := fmt.Sprintf(hclConfigTemplate, tempDir+"/intermediate-ca.crt", tempDir+"/intermediate-ca.key", tempDir+"/root-ca.crt", "2h", tempDir+"/root-ca.crt") hclBody, diagErr := hclsyntax.ParseConfig([]byte(hclConfig), "", hcl.Pos{Line: 1, Column: 1}) require.False(t, diagErr.HasErrors()) @@ -70,6 +72,7 @@ func TestLoadFromProvidersConfig(t *testing.T) { require.NotNil(t, pc) cat := New() + cat.clock = clk err = cat.LoadFromProvidersConfig(pc) require.NoError(t, err) require.NotNil(t, cat.GetBundleSigner()) diff --git a/pkg/harvester/galadrielclient/client.go b/pkg/harvester/galadrielclient/client.go index acd54953..da09db12 100644 --- a/pkg/harvester/galadrielclient/client.go +++ b/pkg/harvester/galadrielclient/client.go @@ -305,13 +305,13 @@ func (c *client) PostBundle(ctx context.Context, bundle *entity.Bundle) error { } sig := util.EncodeToString(bundle.Signature) - cert := util.EncodeToString(bundle.SigningCertificate) + certChain := util.EncodeToString(bundle.SigningCertificateChain) bundlePut := harvester.PutBundleRequest{ - TrustBundle: string(bundle.Data), - Digest: util.EncodeToString(bundle.Digest), - Signature: &sig, - SigningCertificate: &cert, - TrustDomain: bundle.TrustDomainName.String(), + TrustBundle: string(bundle.Data), + Digest: util.EncodeToString(bundle.Digest), + Signature: &sig, + SigningCertificateChain: &certChain, + TrustDomain: bundle.TrustDomainName.String(), } resp, err := c.client.BundlePut(ctx, bundle.TrustDomainName.String(), bundlePut) @@ -492,17 +492,17 @@ func createEntityBundle(trustDomainName string, b *harvester.BundlesUpdatesItem) return nil, fmt.Errorf("failed to decode signature: %v", err) } - signingCert, err := util.DecodeString(b.SigningCertificate) + signingCert, err := util.DecodeString(b.SigningCertificateChain) if err != nil { return nil, fmt.Errorf("failed to decode signing certificate: %v", err) } ret := &entity.Bundle{ - TrustDomainName: td, - Data: bundleData, - Digest: digest, - Signature: signature, - SigningCertificate: signingCert, + TrustDomainName: td, + Data: bundleData, + Digest: digest, + Signature: signature, + SigningCertificateChain: signingCert, } return ret, nil } diff --git a/pkg/harvester/integrity/disk.go b/pkg/harvester/integrity/disk.go index 7f9cddf3..fecf661c 100644 --- a/pkg/harvester/integrity/disk.go +++ b/pkg/harvester/integrity/disk.go @@ -15,9 +15,6 @@ import ( "github.com/jmhodges/clock" ) -// TODO: this should be configurable through a property in the provider in the harvester conf file, based on the bundle TTL to be signed. -const signingCertTTL = 24 * 30 * time.Hour - var ErrInvalidSignature = errors.New("invalid signature") // DiskSigner implements the Signer interface using a CA private key and CA cert stored on disk. @@ -27,8 +24,14 @@ type DiskSigner struct { caPrivateKey crypto.Signer caCert *x509.Certificate + // upstreamChain contains the intermediates certificates necessary to + // chain back to the upstream trust bundle. + upstreamChain []*x509.Certificate + + signingCertTTL time.Duration + // used for testing - clk clock.Clock + clock clock.Clock } // DiskVerifier implements the Verifier interface using a trust bundle stored on disk. @@ -36,30 +39,120 @@ type DiskVerifier struct { trustBundle []*x509.Certificate // used for testing - clk clock.Clock + clock clock.Clock } // DiskSignerConfig is a configuration struct for creating a new DiskSigner type DiskSignerConfig struct { - // the path to the CA private key file - CAPrivateKeyPath string - // the path to the CA certificate file - CACertPath string - Clk clock.Clock + CACertPath string `hcl:"ca_cert_path"` + CAPrivateKeyPath string `hcl:"ca_private_key_path"` + TrustBundlePath string `hcl:"trust_bundle_path"` + SigningCertTTL string `hcl:"signing_cert_ttl"` + Clock clock.Clock } // DiskVerifierConfig is a configuration struct for creating a new DiskVerifier type DiskVerifierConfig struct { - // the path to the public key file - TrustBundlePath string - Clk clock.Clock + TrustBundlePath string `hcl:"trust_bundle_path"` + Clock clock.Clock +} + +// NewDiskSigner creates a new DiskSigner instance without any configuration. +func NewDiskSigner() *DiskSigner { + return &DiskSigner{} +} + +// Configure sets up the DiskSigner with the provided configuration. +func (s *DiskSigner) Configure(config *DiskSignerConfig) error { + if config == nil { + return errors.New(constants.ErrConfigRequired) + } + + var err error + s.signingCertTTL, err = processTTL(config.SigningCertTTL) + if err != nil { + return err + } + + if config.Clock == nil { + config.Clock = clock.New() + } + s.clock = config.Clock + + if config.CACertPath == "" { + return errors.New(constants.ErrCertPathRequired) + } + + if config.CAPrivateKeyPath == "" { + return errors.New(constants.ErrPrivateKeyPathRequired) + } + + key, err := cryptoutil.LoadPrivateKey(config.CAPrivateKeyPath) + if err != nil { + return fmt.Errorf("failed to load CA private key: %w", err) + } + + signer, ok := key.(crypto.Signer) + if !ok { + return errors.New("CA private key is not a signer") + } + + s.caPrivateKey = signer + + certChain, err := cryptoutil.LoadCertificates(config.CACertPath) + if err != nil { + return fmt.Errorf("failed to load CA certificate: %w", err) + } + leafCert := certChain[0] + + if err := cryptoutil.VerifyCertificatePrivateKey(leafCert, key); err != nil { + return fmt.Errorf("certificate verification failed: %w", err) + } + + s.caCert = leafCert + + if err := s.processTrustBundle(config.TrustBundlePath, certChain); err != nil { + return err + } + + return nil +} + +// NewDiskVerifier creates a new DiskVerifier instance without any configuration. +func NewDiskVerifier() *DiskVerifier { + return &DiskVerifier{} +} + +// Configure sets up the DiskVerifier with the provided configuration. +func (v *DiskVerifier) Configure(config *DiskVerifierConfig) error { + if config == nil { + return errors.New(constants.ErrConfigRequired) + } + + if config.Clock == nil { + config.Clock = clock.New() + } + v.clock = config.Clock + + certs, err := cryptoutil.LoadCertificates(config.TrustBundlePath) + if err != nil { + return fmt.Errorf("failed to load trust bundle: %w", err) + } + + if len(certs) == 0 { + return errors.New("trust bundle must contain at least one certificate") + } + + v.trustBundle = certs + + return nil } // Sign computes a signature for the given payload by first hashing it using SHA256, and returns // the signature as a byte slice of bytes along with the certificate chain that has as a leaf the certificate // of the public key that can be used to verify the signature. func (s *DiskSigner) Sign(payload []byte) ([]byte, []*x509.Certificate, error) { - now := s.clk.Now() + now := s.clock.Now() // generate a new private key for signing key, err := cryptoutil.GenerateSigner(cryptoutil.DefaultKeyType) @@ -71,12 +164,13 @@ func (s *DiskSigner) Sign(payload []byte) ([]byte, []*x509.Certificate, error) { if err != nil { return nil, nil, err } - // generate a new certificate for the public key signed by the CA private key + + // generate a certificate to bind the key used to sign the payload template := &x509.Certificate{ SerialNumber: serial, Subject: pkix.Name{CommonName: constants.Galadriel}, NotBefore: now, - NotAfter: now.Add(signingCertTTL), + NotAfter: now.Add(s.signingCertTTL), KeyUsage: x509.KeyUsageDigitalSignature, BasicConstraintsValid: true, IsCA: false, @@ -99,104 +193,93 @@ func (s *DiskSigner) Sign(payload []byte) ([]byte, []*x509.Certificate, error) { return nil, nil, err } - chain := []*x509.Certificate{cert, s.caCert} + chain, err := s.buildCertificateChain(cert) + if err != nil { + return nil, nil, fmt.Errorf("failed to build signing certificate chain: %w", err) + } return signedPayload, chain, nil } // Verify checks if the signature of the given payload matches the expected signature. -// It also verifies that the certificate provided in the signature is signed by a trusted root CA. -func (v *DiskVerifier) Verify(payload, signature []byte, chain []*x509.Certificate) error { +// It also verifies that the signing certificate chain can be chain back to a CA in the trust bundle. +func (v *DiskVerifier) Verify(payload, signature []byte, signingCertificateChain []*x509.Certificate) error { hashed := cryptoutil.CalculateDigest(payload) - if len(chain) == 0 || chain[0] == nil { - return fmt.Errorf("signing certificate is missing") + if len(signingCertificateChain) == 0 || signingCertificateChain[0] == nil { + return errors.New("signing certificate chain is missing") } - roots := x509.NewCertPool() - for _, rootCert := range v.trustBundle { - roots.AddCert(rootCert) - } - - intermediates := x509.NewCertPool() - for _, cert := range chain[1:] { - intermediates.AddCert(cert) - } - - opts := x509.VerifyOptions{ - Roots: roots, - Intermediates: intermediates, - CurrentTime: v.clk.Now(), + roots := v.trustBundle + intermediates := signingCertificateChain[1:] + err := cryptoutil.VerifyCertificateChain(signingCertificateChain, intermediates, roots, v.clock.Now()) + if err != nil { + return fmt.Errorf("failed to verify signing certificate chain: %w", err) } - // verifies the root trust and intermediate certificates - if _, err := chain[0].Verify(opts); err != nil { - return fmt.Errorf("failed to verify chain: %v", err) - } - // verifies signature or artifact - if err := rsa.VerifyPKCS1v15(chain[0].PublicKey.(*rsa.PublicKey), crypto.SHA256, hashed[:], signature); err != nil { + // verifies signature of payload + if err := rsa.VerifyPKCS1v15(signingCertificateChain[0].PublicKey.(*rsa.PublicKey), crypto.SHA256, hashed[:], signature); err != nil { return ErrInvalidSignature } return nil } -// NewDiskSigner creates a new DiskSigner with the given configuration. -func NewDiskSigner(config *DiskSignerConfig) (*DiskSigner, error) { - key, err := cryptoutil.LoadPrivateKey(config.CAPrivateKeyPath) - if err != nil { - return nil, fmt.Errorf("failed to load root CA private key: %w", err) - } - signer, ok := key.(crypto.Signer) - if !ok { - return nil, errors.New("root CA private key is not a signer") - } +func (s *DiskSigner) buildCertificateChain(cert *x509.Certificate) ([]*x509.Certificate, error) { + chain := []*x509.Certificate{cert} - cert, err := cryptoutil.LoadCertificate(config.CACertPath) - if err != nil { - return nil, fmt.Errorf("failed to load root CA certificate: %w", err) + // Always include the certificate used to sign the leaf certificate if it is an intermediate CA + if !cryptoutil.IsSelfSigned(s.caCert) { + chain = append(chain, s.caCert) } - if config.Clk == nil { - config.Clk = clock.New() + // If the CA has a upstreamChain, append the intermediate certificates in the trust bundle to the chain + if len(s.upstreamChain) > 0 { + chain = append(chain, s.upstreamChain...) } - return &DiskSigner{ - caPrivateKey: signer, - caCert: cert, - clk: config.Clk, - }, nil + return chain, nil } -// NewDiskVerifier creates a new DiskVerifier with the given configuration -func NewDiskVerifier(config *DiskVerifierConfig) (*DiskVerifier, error) { - certs, err := cryptoutil.LoadCertificates(config.TrustBundlePath) +func (s *DiskSigner) processTrustBundle(trustBundlePath string, certChain []*x509.Certificate) error { + leafCert := certChain[0] + if trustBundlePath == "" { + return verifySelfSigned(leafCert) + } + + bundle, err := cryptoutil.LoadCertificates(trustBundlePath) if err != nil { - return nil, fmt.Errorf("failed to load trust bundle: %w", err) + return fmt.Errorf("unable to load trust bundle: %w", err) } - if config.Clk == nil { - config.Clk = clock.New() + + intermediates := certChain[1:] + if err := cryptoutil.VerifyCertificateChain([]*x509.Certificate{leafCert}, intermediates, bundle, s.clock.Now()); err != nil { + return fmt.Errorf("certificate chain verification failed: %w", err) } - return &DiskVerifier{ - trustBundle: certs, - clk: config.Clk, - }, nil + s.upstreamChain = intermediates + + return nil } -// NewDiskSignerConfig creates a new DiskSignerConfig function with the given CA private key and CA certificate paths -func NewDiskSignerConfig(CAPrivateKeyPath, CACertPath string) *DiskSignerConfig { - return &DiskSignerConfig{ - CAPrivateKeyPath: CAPrivateKeyPath, - CACertPath: CACertPath, - Clk: clock.New(), +func verifySelfSigned(cert *x509.Certificate) error { + if !cryptoutil.IsSelfSigned(cert) { + return errors.New(constants.ErrTrustBundleRequired) } + return nil } -// NewDiskVerifierConfig function creates a new DiskVerifierConfig function with the given trust bundle path -func NewDiskVerifierConfig(TrustBundlePath string) *DiskVerifierConfig { - return &DiskVerifierConfig{ - TrustBundlePath: TrustBundlePath, - Clk: clock.New(), +func processTTL(ttl string) (time.Duration, error) { + if ttl == "" { + return 0, errors.New(constants.ErrTTLRequired) } + duration, err := time.ParseDuration(ttl) + if err != nil { + return 0, fmt.Errorf("failed to parse signing cert TTL: %w", err) + } + if duration <= 0 { + return 0, errors.New("signing cert TTL must be greater than 0") + } + + return duration, nil } diff --git a/pkg/harvester/integrity/disk_test.go b/pkg/harvester/integrity/disk_test.go index 98ab62d8..7fb14472 100644 --- a/pkg/harvester/integrity/disk_test.go +++ b/pkg/harvester/integrity/disk_test.go @@ -1,13 +1,11 @@ package integrity import ( - "crypto" - "crypto/x509" - "crypto/x509/pkix" + "os" "testing" "time" - "github.com/HewlettPackard/galadriel/pkg/common/cryptoutil" + "github.com/HewlettPackard/galadriel/pkg/common/constants" "github.com/HewlettPackard/galadriel/test/certtest" "github.com/jmhodges/clock" "github.com/stretchr/testify/assert" @@ -16,172 +14,301 @@ import ( var clk = clock.NewFake() -const ( - rootCACert = "/root-ca.crt" - rootCAKey = "/root-ca.key" -) - -func TestDiskSignerAndVerifierUsingRootCA(t *testing.T) { - var signer Signer - - caTemplate, err := cryptoutil.CreateCATemplate(clk, nil, pkix.Name{CommonName: "test-ca"}, 1*time.Hour) - require.NoError(t, err) - - rootCert, privateKey, err := cryptoutil.SelfSignX509(caTemplate) - require.NoError(t, err) - signerKey, ok := privateKey.(crypto.Signer) - require.True(t, ok) - - // create a DiskSigner using the root key and the root certificate - signer = &DiskSigner{ - caPrivateKey: signerKey, - caCert: rootCert, - clk: clk, - } - - createPayloadSignVerify(t, signer, rootCert) +func TestNewDiskSigner(t *testing.T) { + ds := NewDiskSigner() + assert.NotNil(t, ds) +} +func TestNewDiskVerifier(t *testing.T) { + dv := NewDiskVerifier() + assert.NotNil(t, dv) } -func TestDiskSignerAndVerifierUsingIntermediateCA(t *testing.T) { - var signer Signer +func TestSignAndVerifyUsingRootCA(t *testing.T) { + tempDir := setupTest(t) - rootCaTemplate, err := cryptoutil.CreateCATemplate(clk, nil, pkix.Name{CommonName: "test-ca"}, 1*time.Hour) - require.NoError(t, err) - - rootCert, rootPrivateKey, err := cryptoutil.SelfSignX509(rootCaTemplate) - require.NoError(t, err) + diskSignerConfig := &DiskSignerConfig{ + CACertPath: tempDir + "/root-ca.crt", + CAPrivateKeyPath: tempDir + "/root-ca.key", + TrustBundlePath: "", + SigningCertTTL: "5m", + Clock: clk, + } - // create key pair for intermediate CA - intermediateKey, err := cryptoutil.GenerateSigner(cryptoutil.DefaultKeyType) - require.NoError(t, err) - intermediateCaTemplate, err := cryptoutil.CreateCATemplate(clk, intermediateKey.Public(), pkix.Name{CommonName: "test-intermediate-ca"}, 1*time.Hour) - require.NoError(t, err) - intermediateCert, err := cryptoutil.SignX509(intermediateCaTemplate, rootCaTemplate, rootPrivateKey) + diskSigner := NewDiskSigner() + err := diskSigner.Configure(diskSignerConfig) require.NoError(t, err) - // create a DiskSigner using intermediateKey and the intermediate certificate - signer = &DiskSigner{ - caPrivateKey: intermediateKey, - caCert: intermediateCert, - clk: clk, + diskVerifierConfig := &DiskVerifierConfig{ + TrustBundlePath: tempDir + "/root-ca.crt", + Clock: clk, } - createPayloadSignVerify(t, signer, rootCert) -} - -// TestNewDiskSignerConfig tests for a new config with string parameters for the key and cert paths -func TestNewDisSignerConfig(t *testing.T) { + diskVerifier := NewDiskVerifier() + err = diskVerifier.Configure(diskVerifierConfig) + require.NoError(t, err) - // create selfsigned root CA - tmpDir := certtest.CreateTestCACertificates(t, clk) - assert.NotNil(t, tmpDir) + // payload to sign + payload := []byte("test payload") - tmpCertPath := tmpDir + rootCACert - tmpKeyPath := tmpDir + rootCAKey + // Sign the payload using the disk signer + signature, signingChain, err := diskSigner.Sign(payload) + require.NoError(t, err) + require.NotNil(t, signature) + require.NotNil(t, signingChain) + assert.Equal(t, 1, len(signingChain)) - newConf := NewDiskSignerConfig(tmpKeyPath, tmpCertPath) - assert.NotNil(t, newConf) - assert.Equal(t, tmpCertPath, newConf.CACertPath) - assert.Equal(t, tmpKeyPath, newConf.CAPrivateKeyPath) + // Verify the signature using the disk verifier + err = diskVerifier.Verify(payload, signature, signingChain) + require.NoError(t, err) + alteredPayload := []byte("altered payload") + err = diskVerifier.Verify(alteredPayload, signature, signingChain) + require.Error(t, err) + assert.Equal(t, ErrInvalidSignature, err) } -// TestNewDisVerifierConfig test for a new config string parameters for the trust bundle path -func TestNewDisVerifierConfig(t *testing.T) { +func TestSignAndVerifyUsingIntermediateCAs(t *testing.T) { + tempDir := setupTest(t) - // create selfsigned root CA - tmpDir := certtest.CreateTestCACertificates(t, clk) - assert.NotNil(t, tmpDir) + diskSignerConfig := &DiskSignerConfig{ + CACertPath: tempDir + "/chain.crt", + CAPrivateKeyPath: tempDir + "/intermediate-ca-2.key", + TrustBundlePath: tempDir + "/bundle.crt", + SigningCertTTL: "5m", + Clock: clk, + } - tmpCertPath := tmpDir + rootCACert + diskSigner := NewDiskSigner() + err := diskSigner.Configure(diskSignerConfig) + require.NoError(t, err) - newConf := NewDiskVerifierConfig(tmpCertPath) - assert.NotNil(t, newConf) - assert.Equal(t, tmpCertPath, newConf.TrustBundlePath) -} + diskVerifierConfig := &DiskVerifierConfig{ + TrustBundlePath: tempDir + "/bundle.crt", + Clock: clk, + } + diskVerifier := NewDiskVerifier() + err = diskVerifier.Configure(diskVerifierConfig) + require.NoError(t, err) -// TestNewDiskSigner tests the creation of a NewDiskSigner with DiskSignerConfig -func TestNewDiskSigner(t *testing.T) { + // payload to sign + payload := []byte("test payload") - // create selfsigned root CA - tmpDir := certtest.CreateTestCACertificates(t, clk) - assert.NotNil(t, tmpDir) + // Sign the payload using the disk signer + signature, signingChain, err := diskSigner.Sign(payload) + require.NoError(t, err) + require.NotNil(t, signature) + require.NotNil(t, signingChain) + assert.Equal(t, 3, len(signingChain)) - tmpCertPath := tmpDir + rootCACert - tmpKeyPath := tmpDir + rootCAKey + // Verify the signature using the disk verifier + err = diskVerifier.Verify(payload, signature, signingChain) + require.NoError(t, err) - newConf := NewDiskSignerConfig(tmpKeyPath, tmpCertPath) - assert.NotNil(t, newConf) + alteredPayload := []byte("altered payload") + err = diskVerifier.Verify(alteredPayload, signature, signingChain) + require.Error(t, err) + assert.Equal(t, ErrInvalidSignature, err) - newSigner, err := NewDiskSigner(newConf) - assert.NotNil(t, newSigner) - assert.NoError(t, err) + // remove last cert from the chain so it doesn't chain back to the root + signingChain = signingChain[:len(signingChain)-1] + err = diskVerifier.Verify(payload, signature, signingChain) + require.Error(t, err) + assert.Contains(t, err.Error(), "failed to verify signing certificate chain") } -// TestNewDiskSignerWithInvalidConfig tests for the error when paths in config are invalid -func TestNewDiskSignerWithInvalidConfig(t *testing.T) { - - newConf := NewDiskSignerConfig("invalidpath", "invalidpath") - assert.NotNil(t, newConf) +func TestConfigureDiskSigner(t *testing.T) { + tempDir := setupTest(t) + + testCases := []struct { + name string + config DiskSignerConfig + err string + expectedBundleLength int + }{ + { + name: "WithRootCA", + config: DiskSignerConfig{ + CAPrivateKeyPath: tempDir + "/root-ca.key", + CACertPath: tempDir + "/root-ca.crt", + TrustBundlePath: "", + SigningCertTTL: "42h", + }, + expectedBundleLength: 0, + }, + { + name: "WithIntermediateCAAndRootCA", + config: DiskSignerConfig{ + CAPrivateKeyPath: tempDir + "/intermediate-ca.key", + CACertPath: tempDir + "/intermediate-ca.crt", + TrustBundlePath: tempDir + "/root-ca.crt", + SigningCertTTL: "5h", + }, + expectedBundleLength: 0, + }, + { + name: "WithIntermediateCAAndTrustBundle", + config: DiskSignerConfig{ + CAPrivateKeyPath: tempDir + "/intermediate-ca-2.key", + CACertPath: tempDir + "/chain.crt", + TrustBundlePath: tempDir + "/bundle.crt", + SigningCertTTL: "12h", + }, + expectedBundleLength: 1, + }, + { + name: "WithIntermediateCADontChainBack", + config: DiskSignerConfig{ + CAPrivateKeyPath: tempDir + "/other-ca.key", + CACertPath: tempDir + "/other-ca.crt", + TrustBundlePath: tempDir + "/root-ca.crt", + SigningCertTTL: "42h", + }, + err: "unable to chain the certificate to a trusted CA", + }, + { + name: "CertAndPrivateKeyNotMatch", + config: DiskSignerConfig{ + CAPrivateKeyPath: tempDir + "/other-ca.key", + CACertPath: tempDir + "/root-ca.crt", + SigningCertTTL: "42h", + }, + err: "certificate public key does not match private key", + }, + { + name: "NoSelfSigned", + config: DiskSignerConfig{ + CAPrivateKeyPath: tempDir + "/intermediate-ca.key", + CACertPath: tempDir + "/intermediate-ca.crt", + SigningCertTTL: "42h", + }, + err: constants.ErrTrustBundleRequired, + }, + { + name: "NoIntermediateCACert", + config: DiskSignerConfig{ + CAPrivateKeyPath: tempDir + "/intermediate-ca.key", + CACertPath: "", + SigningCertTTL: "42h", + }, + err: constants.ErrCertPathRequired, + }, + { + name: "NoIntermediateCAPrivateKey", + config: DiskSignerConfig{ + CAPrivateKeyPath: "", + CACertPath: tempDir + "/intermediate-ca.crt", + SigningCertTTL: "42h", + }, + err: constants.ErrPrivateKeyPathRequired, + }, + { + name: "EmptyTTL", + config: DiskSignerConfig{ + CAPrivateKeyPath: tempDir + "/root-ca.key", + CACertPath: tempDir + "/root-ca.crt", + SigningCertTTL: "", + }, + err: constants.ErrTTLRequired, + }, + { + name: "WithNonExistentCertificatePath", + config: DiskSignerConfig{ + CAPrivateKeyPath: tempDir + "/root-ca.key", + CACertPath: tempDir + "/non-existent.crt", + SigningCertTTL: "1h", + }, + err: "failed to load CA certificate", + }, + { + name: "WithNonExistentKeyPath", + config: DiskSignerConfig{ + CAPrivateKeyPath: tempDir + "/non-existeng.key", + CACertPath: tempDir + "/root-ca.crt", + SigningCertTTL: "1h", + }, + err: "failed to load CA private key", + }, + } - // create a new signer with invalid config - newConf.CACertPath = "invalid" - newSigner, err := NewDiskSigner(newConf) - assert.Nil(t, newSigner) - assert.Error(t, err) + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + ds := NewDiskSigner() + tc.config.Clock = clk + + err := ds.Configure(&tc.config) + if tc.err != "" { + require.Error(t, err) + assert.Contains(t, err.Error(), tc.err) + } else { + require.NoError(t, err) + assert.Equal(t, tc.expectedBundleLength, len(ds.upstreamChain)) + assert.Equal(t, parseDuration(t, tc.config.SigningCertTTL), ds.signingCertTTL) + } + }) + } } -// TestNewDiskVerifier tests the creation of a NewDiskVerifier with DiskVerifierConfig -func TestNewDiskVerifier(t *testing.T) { - - // create selfsigned root CA - tmpDir := certtest.CreateTestCACertificates(t, clk) - assert.NotNil(t, tmpDir) - - tmpCertPath := tmpDir + rootCACert - - newConf := NewDiskVerifierConfig(tmpCertPath) - assert.NotNil(t, newConf) +func TestConfigureDiskVerifier(t *testing.T) { + tempDir := setupTest(t) + + testCases := []struct { + name string + config DiskVerifierConfig + err string + expectedBundleLength int + }{ + { + name: "WithOneRootCA", + config: DiskVerifierConfig{ + TrustBundlePath: tempDir + "/root-ca.crt", + }, + expectedBundleLength: 1, + }, + { + name: "WithBundle", + config: DiskVerifierConfig{ + TrustBundlePath: tempDir + "/bundle.crt", + }, + expectedBundleLength: 2, + }, + { + name: "WithNonExistentPath", + config: DiskVerifierConfig{ + TrustBundlePath: tempDir + "/non-existent.crt", + }, + err: "failed to load trust bundle", + }, + } - newVerifier, err := NewDiskVerifier(newConf) - assert.NotNil(t, newVerifier) - assert.NoError(t, err) + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + ds := NewDiskVerifier() + tc.config.Clock = clk + + err := ds.Configure(&tc.config) + if tc.err != "" { + require.Error(t, err) + assert.Contains(t, err.Error(), tc.err) + } else { + require.NoError(t, err) + assert.Equal(t, tc.expectedBundleLength, len(ds.trustBundle)) + } + }) + } } -func createPayloadSignVerify(t *testing.T, signer Signer, rootCert *x509.Certificate) { - var verifier Verifier - // create a test payload - payload := []byte("test payload") - otherPayload := []byte("other payload") - - // sign the payload using the caPrivateKey - signature, signingCert, err := signer.Sign(payload) - require.NoError(t, err) - require.NotNil(t, signingCert) - - // sign the payload using the caPrivateKey - otherSignature, otherCert, err := signer.Sign(otherPayload) +func parseDuration(t *testing.T, d string) time.Duration { + duration, err := time.ParseDuration(d) require.NoError(t, err) - require.NotNil(t, otherCert) + return duration +} - // create a verifier using the root certificate in the trust bundle - verifier = &DiskVerifier{ - trustBundle: []*x509.Certificate{rootCert}, - clk: clk, +func setupTest(t *testing.T) string { + tempDir := certtest.CreateTestCACertificates(t, clk) + cleanup := func() { + os.RemoveAll(tempDir) } + t.Cleanup(cleanup) - // verify the signature using the verifier - err = verifier.Verify(payload, signature, signingCert) - require.NoError(t, err) - - err = verifier.Verify(otherPayload, otherSignature, otherCert) - require.NoError(t, err) - - err = verifier.Verify(otherPayload, signature, signingCert) - require.Error(t, err) - assert.Equal(t, ErrInvalidSignature, err) - - err = verifier.Verify(payload, otherSignature, otherCert) - require.Error(t, err) - assert.Equal(t, ErrInvalidSignature, err) + return tempDir } diff --git a/pkg/server/api/harvester/harvester.gen.go b/pkg/server/api/harvester/harvester.gen.go index b62b6b4d..a123b2fa 100644 --- a/pkg/server/api/harvester/harvester.gen.go +++ b/pkg/server/api/harvester/harvester.gen.go @@ -40,8 +40,8 @@ type BundlesUpdatesItem struct { // Signature base64 encoded signature of the bundle Signature externalRef0.Signature `json:"signature"` - // SigningCertificate X.509 certificate in PEM format - SigningCertificate externalRef0.Certificate `json:"signing_certificate"` + // SigningCertificateChain X.509 certificate chain in PEM format + SigningCertificateChain externalRef0.CertificateChain `json:"signing_certificate_chain"` // TrustBundle SPIFFE Trust bundle in JSON format TrustBundle externalRef0.TrustBundle `json:"trust_bundle"` @@ -86,8 +86,8 @@ type PutBundleRequest struct { // Signature base64 encoded signature of the bundle Signature *externalRef0.Signature `json:"signature,omitempty"` - // SigningCertificate X.509 certificate in PEM format - SigningCertificate *externalRef0.Certificate `json:"signing_certificate,omitempty"` + // SigningCertificateChain X.509 certificate chain in PEM format + SigningCertificateChain *externalRef0.CertificateChain `json:"signing_certificate_chain,omitempty"` // TrustBundle SPIFFE Trust bundle in JSON format TrustBundle externalRef0.TrustBundle `json:"trust_bundle"` @@ -1338,109 +1338,103 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "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", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/pkg/server/api/harvester/harvester.yaml b/pkg/server/api/harvester/harvester.yaml index 47a3bae2..f9b45d1e 100644 --- a/pkg/server/api/harvester/harvester.yaml +++ b/pkg/server/api/harvester/harvester.yaml @@ -246,8 +246,8 @@ components: $ref: '../../../common/api/schemas.yaml#/components/schemas/TrustBundle' signature: $ref: '../../../common/api/schemas.yaml#/components/schemas/Signature' - signing_certificate: - $ref: '../../../common/api/schemas.yaml#/components/schemas/Certificate' + signing_certificate_chain: + $ref: '../../../common/api/schemas.yaml#/components/schemas/CertificateChain' digest: $ref: '../../../common/api/schemas.yaml#/components/schemas/BundleDigest' PostBundleSyncRequest: @@ -277,7 +277,7 @@ components: trust_domain_1: { signature: "NLHJupZn8KxFoJmSiJDCP+UuoSJOlhMK1HYIjc6YP75ve15PcMJ7zq1JLRXFzXtM0zf0ScLbZ1nYYGvQmgW+GJAx5PsmSq3m1kjrx0fFJD0EDqVZhazoYIos84Pa8qG/cWe05s1rHoYY53wO231ZGktkH56KnydHD2wwefyQCpA=", trust_bundle: "", - signing_certificate: "-----BEGIN CERTIFICATE----- + signing_certificate_chain: "-----BEGIN CERTIFICATE----- MIIDuzCCAqMCFH+T4VhUJm/YDc927qIA591wFjQ/MA0GCSqGSIb3DQEBCwUAMIGZ MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0b24x KzApBgNVBAoMIkhld2xldHQgUGFja2FyZCBFbnRlcnByaXNlIENvbXBhbnkxHjAc @@ -342,7 +342,7 @@ components: - trust_bundle - digest - signature - - signing_certificate + - signing_certificate_chain properties: trust_bundle: $ref: '../../../common/api/schemas.yaml#/components/schemas/TrustBundle' @@ -350,8 +350,8 @@ components: $ref: '../../../common/api/schemas.yaml#/components/schemas/BundleDigest' signature: $ref: '../../../common/api/schemas.yaml#/components/schemas/Signature' - signing_certificate: - $ref: '../../../common/api/schemas.yaml#/components/schemas/Certificate' + signing_certificate_chain: + $ref: '../../../common/api/schemas.yaml#/components/schemas/CertificateChain' securitySchemes: harvester_auth: $ref: '../../../common/api/schemas.yaml#/components/securitySchemes/harvester_auth' diff --git a/pkg/server/api/harvester/helper.go b/pkg/server/api/harvester/helper.go index d7e77ab4..19c48115 100644 --- a/pkg/server/api/harvester/helper.go +++ b/pkg/server/api/harvester/helper.go @@ -31,18 +31,18 @@ func (b PutBundleRequest) ToEntity() (*entity.Bundle, error) { } var cert []byte - if b.SigningCertificate != nil { - cert, err = encoding.DecodeFromBase64(*b.SigningCertificate) + if b.SigningCertificateChain != nil { + cert, err = encoding.DecodeFromBase64(*b.SigningCertificateChain) if err != nil { return nil, fmt.Errorf("cannot decode signing certificate: %w", err) } } return &entity.Bundle{ - Data: []byte(b.TrustBundle), - Digest: dig, - Signature: sig, - TrustDomainName: td, - SigningCertificate: cert, + Data: []byte(b.TrustBundle), + Digest: dig, + Signature: sig, + TrustDomainName: td, + SigningCertificateChain: cert, }, nil } diff --git a/pkg/server/api/harvester/helper_test.go b/pkg/server/api/harvester/helper_test.go index 2391dd63..7f05dd44 100644 --- a/pkg/server/api/harvester/helper_test.go +++ b/pkg/server/api/harvester/helper_test.go @@ -19,17 +19,17 @@ func TestBundlePutToEntity(t *testing.T) { assert.Nil(t, bundle) }) - t.Run("Full fill correctly the bundle entity model", func(t *testing.T) { + t.Run("Fulfill correctly the bundle entity model", func(t *testing.T) { bundleData := "test-bundle" digest := cryptoutil.CalculateDigest([]byte(bundleData)) sig := encoding.EncodeToBase64([]byte("test-signature")) cert := encoding.EncodeToBase64([]byte("test-certificate")) bundlePut := PutBundleRequest{ - TrustBundle: bundleData, - Digest: encoding.EncodeToBase64(digest), - Signature: &sig, - TrustDomain: "test.com", - SigningCertificate: &cert, + TrustBundle: bundleData, + Digest: encoding.EncodeToBase64(digest), + Signature: &sig, + TrustDomain: "test.com", + SigningCertificateChain: &cert, } bundle, err := bundlePut.ToEntity() @@ -40,6 +40,6 @@ func TestBundlePutToEntity(t *testing.T) { assert.Equal(t, []byte(bundlePut.TrustBundle), bundle.Data) assert.Equal(t, digest, bundle.Digest) assert.Equal(t, []byte("test-signature"), bundle.Signature) - assert.Equal(t, []byte("test-certificate"), bundle.SigningCertificate) + assert.Equal(t, []byte("test-certificate"), bundle.SigningCertificateChain) }) } diff --git a/pkg/server/catalog/catalog.go b/pkg/server/catalog/catalog.go index fad9c5d7..7385304c 100644 --- a/pkg/server/catalog/catalog.go +++ b/pkg/server/catalog/catalog.go @@ -27,7 +27,7 @@ type ProvidersRepository struct { x509ca x509ca.X509CA keyManager keymanager.KeyManager - clk clock.Clock + clock clock.Clock } // ProvidersConfig holds the HCL configuration for the providers. @@ -116,7 +116,7 @@ func (c *ProvidersRepository) GetKeyManager() keymanager.KeyManager { func (r *ProvidersRepository) loadX509CA(c *providerConfig) (x509ca.X509CA, error) { switch c.Name { case "disk": - x509CA, err := makeDiskX509CA(c, r.clk) + x509CA, err := makeDiskX509CA(c, r.clock) if err != nil { return nil, fmt.Errorf("error creating disk X509CA: %w", err) } diff --git a/pkg/server/catalog/catalog_test.go b/pkg/server/catalog/catalog_test.go index 310e3e86..607b0a88 100644 --- a/pkg/server/catalog/catalog_test.go +++ b/pkg/server/catalog/catalog_test.go @@ -69,7 +69,7 @@ func TestLoadFromProvidersConfig(t *testing.T) { require.NotNil(t, pc) cat := New() - cat.clk = clk + cat.clock = clk err = cat.LoadFromProvidersConfig(pc) require.NoError(t, err) require.NotNil(t, cat.GetDatastore()) diff --git a/pkg/server/db/postgres/bundles.sql.go b/pkg/server/db/postgres/bundles.sql.go index f2cfae87..aecc84b7 100644 --- a/pkg/server/db/postgres/bundles.sql.go +++ b/pkg/server/db/postgres/bundles.sql.go @@ -13,18 +13,18 @@ import ( ) const createBundle = `-- name: CreateBundle :one -INSERT INTO bundles(data, digest, signature, signing_certificate, trust_domain_id, created_at) +INSERT INTO bundles(data, digest, signature, signing_certificate_chain, trust_domain_id, created_at) VALUES ($1, $2, $3, $4, $5, $6) -RETURNING id, trust_domain_id, data, digest, signature, signing_certificate, created_at, updated_at +RETURNING id, trust_domain_id, data, digest, signature, signing_certificate_chain, created_at, updated_at ` type CreateBundleParams struct { - Data []byte - Digest []byte - Signature []byte - SigningCertificate []byte - TrustDomainID pgtype.UUID - CreatedAt time.Time + Data []byte + Digest []byte + Signature []byte + SigningCertificateChain []byte + TrustDomainID pgtype.UUID + CreatedAt time.Time } func (q *Queries) CreateBundle(ctx context.Context, arg CreateBundleParams) (Bundle, error) { @@ -32,7 +32,7 @@ func (q *Queries) CreateBundle(ctx context.Context, arg CreateBundleParams) (Bun arg.Data, arg.Digest, arg.Signature, - arg.SigningCertificate, + arg.SigningCertificateChain, arg.TrustDomainID, arg.CreatedAt, ) @@ -43,7 +43,7 @@ func (q *Queries) CreateBundle(ctx context.Context, arg CreateBundleParams) (Bun &i.Data, &i.Digest, &i.Signature, - &i.SigningCertificate, + &i.SigningCertificateChain, &i.CreatedAt, &i.UpdatedAt, ) @@ -62,7 +62,7 @@ func (q *Queries) DeleteBundle(ctx context.Context, id pgtype.UUID) error { } const findBundleByID = `-- name: FindBundleByID :one -SELECT id, trust_domain_id, data, digest, signature, signing_certificate, created_at, updated_at +SELECT id, trust_domain_id, data, digest, signature, signing_certificate_chain, created_at, updated_at FROM bundles WHERE id = $1 ` @@ -76,7 +76,7 @@ func (q *Queries) FindBundleByID(ctx context.Context, id pgtype.UUID) (Bundle, e &i.Data, &i.Digest, &i.Signature, - &i.SigningCertificate, + &i.SigningCertificateChain, &i.CreatedAt, &i.UpdatedAt, ) @@ -84,7 +84,7 @@ func (q *Queries) FindBundleByID(ctx context.Context, id pgtype.UUID) (Bundle, e } const findBundleByTrustDomainID = `-- name: FindBundleByTrustDomainID :one -SELECT id, trust_domain_id, data, digest, signature, signing_certificate, created_at, updated_at +SELECT id, trust_domain_id, data, digest, signature, signing_certificate_chain, created_at, updated_at FROM bundles WHERE trust_domain_id = $1 ` @@ -98,7 +98,7 @@ func (q *Queries) FindBundleByTrustDomainID(ctx context.Context, trustDomainID p &i.Data, &i.Digest, &i.Signature, - &i.SigningCertificate, + &i.SigningCertificateChain, &i.CreatedAt, &i.UpdatedAt, ) @@ -106,7 +106,7 @@ func (q *Queries) FindBundleByTrustDomainID(ctx context.Context, trustDomainID p } const listBundles = `-- name: ListBundles :many -SELECT id, trust_domain_id, data, digest, signature, signing_certificate, created_at, updated_at +SELECT id, trust_domain_id, data, digest, signature, signing_certificate_chain, created_at, updated_at FROM bundles ORDER BY created_at DESC ` @@ -126,7 +126,7 @@ func (q *Queries) ListBundles(ctx context.Context) ([]Bundle, error) { &i.Data, &i.Digest, &i.Signature, - &i.SigningCertificate, + &i.SigningCertificateChain, &i.CreatedAt, &i.UpdatedAt, ); err != nil { @@ -148,18 +148,18 @@ UPDATE bundles SET data = $2, digest = $3, signature = $4, - signing_certificate = $5, + signing_certificate_chain = $5, updated_at = now() WHERE id = $1 -RETURNING id, trust_domain_id, data, digest, signature, signing_certificate, created_at, updated_at +RETURNING id, trust_domain_id, data, digest, signature, signing_certificate_chain, created_at, updated_at ` type UpdateBundleParams struct { - ID pgtype.UUID - Data []byte - Digest []byte - Signature []byte - SigningCertificate []byte + ID pgtype.UUID + Data []byte + Digest []byte + Signature []byte + SigningCertificateChain []byte } func (q *Queries) UpdateBundle(ctx context.Context, arg UpdateBundleParams) (Bundle, error) { @@ -168,7 +168,7 @@ func (q *Queries) UpdateBundle(ctx context.Context, arg UpdateBundleParams) (Bun arg.Data, arg.Digest, arg.Signature, - arg.SigningCertificate, + arg.SigningCertificateChain, ) var i Bundle err := row.Scan( @@ -177,7 +177,7 @@ func (q *Queries) UpdateBundle(ctx context.Context, arg UpdateBundleParams) (Bun &i.Data, &i.Digest, &i.Signature, - &i.SigningCertificate, + &i.SigningCertificateChain, &i.CreatedAt, &i.UpdatedAt, ) diff --git a/pkg/server/db/postgres/datastore.go b/pkg/server/db/postgres/datastore.go index 7416365e..0ec13cbb 100644 --- a/pkg/server/db/postgres/datastore.go +++ b/pkg/server/db/postgres/datastore.go @@ -520,12 +520,12 @@ func (d *Datastore) createBundle(ctx context.Context, req *entity.Bundle) (*Bund return nil, err } params := CreateBundleParams{ - Data: req.Data, - Digest: req.Digest, - Signature: req.Signature, - SigningCertificate: req.SigningCertificate, - TrustDomainID: pgTrustDomainID, - CreatedAt: req.CreatedAt, + Data: req.Data, + Digest: req.Digest, + Signature: req.Signature, + SigningCertificateChain: req.SigningCertificateChain, + TrustDomainID: pgTrustDomainID, + CreatedAt: req.CreatedAt, } bundle, err := d.querier.CreateBundle(ctx, params) @@ -542,11 +542,11 @@ func (d *Datastore) updateBundle(ctx context.Context, req *entity.Bundle) (*Bund return nil, err } params := UpdateBundleParams{ - ID: pgID, - Data: req.Data, - Digest: req.Digest, - Signature: req.Signature, - SigningCertificate: req.SigningCertificate, + ID: pgID, + Data: req.Data, + Digest: req.Digest, + Signature: req.Signature, + SigningCertificateChain: req.SigningCertificateChain, } bundle, err := d.querier.UpdateBundle(ctx, params) diff --git a/pkg/server/db/postgres/helpers.go b/pkg/server/db/postgres/helpers.go index 6e03860c..6e23736a 100644 --- a/pkg/server/db/postgres/helpers.go +++ b/pkg/server/db/postgres/helpers.go @@ -57,14 +57,14 @@ func (b Bundle) ToEntity() (*entity.Bundle, error) { } return &entity.Bundle{ - ID: id, - Data: b.Data, - Digest: b.Digest, - Signature: b.Signature, - SigningCertificate: b.SigningCertificate, - TrustDomainID: b.TrustDomainID.Bytes, - CreatedAt: b.CreatedAt, - UpdatedAt: b.UpdatedAt, + ID: id, + Data: b.Data, + Digest: b.Digest, + Signature: b.Signature, + SigningCertificateChain: b.SigningCertificateChain, + TrustDomainID: b.TrustDomainID.Bytes, + CreatedAt: b.CreatedAt, + UpdatedAt: b.UpdatedAt, }, nil } diff --git a/pkg/server/db/postgres/migrations/1_initialize_schema.up.sql b/pkg/server/db/postgres/migrations/1_initialize_schema.up.sql index 529db5af..0a7b183b 100644 --- a/pkg/server/db/postgres/migrations/1_initialize_schema.up.sql +++ b/pkg/server/db/postgres/migrations/1_initialize_schema.up.sql @@ -25,14 +25,14 @@ CREATE TABLE IF NOT EXISTS relationships CREATE TABLE IF NOT EXISTS bundles ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - trust_domain_id UUID NOT NULL UNIQUE, - data BYTEA NOT NULL, - digest BYTEA NOT NULL, - signature BYTEA, - signing_certificate BYTEA, - created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), - updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now() + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + trust_domain_id UUID NOT NULL UNIQUE, + data BYTEA NOT NULL, + digest BYTEA NOT NULL, + signature BYTEA, + signing_certificate_chain BYTEA, + created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), + updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now() ); CREATE TABLE IF NOT EXISTS join_tokens diff --git a/pkg/server/db/postgres/models.gen.go b/pkg/server/db/postgres/models.gen.go index 6db4a6a0..020d345c 100644 --- a/pkg/server/db/postgres/models.gen.go +++ b/pkg/server/db/postgres/models.gen.go @@ -57,14 +57,14 @@ func (ns NullConsentStatus) Value() (driver.Value, error) { } type Bundle struct { - ID pgtype.UUID - TrustDomainID pgtype.UUID - Data []byte - Digest []byte - Signature []byte - SigningCertificate []byte - CreatedAt time.Time - UpdatedAt time.Time + ID pgtype.UUID + TrustDomainID pgtype.UUID + Data []byte + Digest []byte + Signature []byte + SigningCertificateChain []byte + CreatedAt time.Time + UpdatedAt time.Time } type JoinToken struct { diff --git a/pkg/server/db/postgres/queries/bundles.sql b/pkg/server/db/postgres/queries/bundles.sql index ccca356e..fb39bbb5 100644 --- a/pkg/server/db/postgres/queries/bundles.sql +++ b/pkg/server/db/postgres/queries/bundles.sql @@ -1,5 +1,5 @@ -- name: CreateBundle :one -INSERT INTO bundles(data, digest, signature, signing_certificate, trust_domain_id, created_at) +INSERT INTO bundles(data, digest, signature, signing_certificate_chain, trust_domain_id, created_at) VALUES ($1, $2, $3, $4, $5, $6) RETURNING *; @@ -8,7 +8,7 @@ UPDATE bundles SET data = $2, digest = $3, signature = $4, - signing_certificate = $5, + signing_certificate_chain = $5, updated_at = now() WHERE id = $1 RETURNING *; diff --git a/pkg/server/db/sqlite/bundles.sql.go b/pkg/server/db/sqlite/bundles.sql.go index 4a898034..036695f8 100644 --- a/pkg/server/db/sqlite/bundles.sql.go +++ b/pkg/server/db/sqlite/bundles.sql.go @@ -11,19 +11,19 @@ import ( ) const createBundle = `-- name: CreateBundle :one -INSERT INTO bundles(id, data, digest, signature, signing_certificate, trust_domain_id, created_at) +INSERT INTO bundles(id, data, digest, signature, signing_certificate_chain, trust_domain_id, created_at) VALUES (?, ?, ?, ?, ?, ?, ?) -RETURNING id, trust_domain_id, data, digest, signature, signing_certificate, created_at, updated_at +RETURNING id, trust_domain_id, data, digest, signature, signing_certificate_chain, created_at, updated_at ` type CreateBundleParams struct { - ID string - Data []byte - Digest []byte - Signature []byte - SigningCertificate []byte - TrustDomainID string - CreatedAt time.Time + ID string + Data []byte + Digest []byte + Signature []byte + SigningCertificateChain []byte + TrustDomainID string + CreatedAt time.Time } func (q *Queries) CreateBundle(ctx context.Context, arg CreateBundleParams) (Bundle, error) { @@ -32,7 +32,7 @@ func (q *Queries) CreateBundle(ctx context.Context, arg CreateBundleParams) (Bun arg.Data, arg.Digest, arg.Signature, - arg.SigningCertificate, + arg.SigningCertificateChain, arg.TrustDomainID, arg.CreatedAt, ) @@ -43,7 +43,7 @@ func (q *Queries) CreateBundle(ctx context.Context, arg CreateBundleParams) (Bun &i.Data, &i.Digest, &i.Signature, - &i.SigningCertificate, + &i.SigningCertificateChain, &i.CreatedAt, &i.UpdatedAt, ) @@ -62,7 +62,7 @@ func (q *Queries) DeleteBundle(ctx context.Context, id string) error { } const findBundleByID = `-- name: FindBundleByID :one -SELECT id, trust_domain_id, data, digest, signature, signing_certificate, created_at, updated_at +SELECT id, trust_domain_id, data, digest, signature, signing_certificate_chain, created_at, updated_at FROM bundles WHERE id = ? ` @@ -76,7 +76,7 @@ func (q *Queries) FindBundleByID(ctx context.Context, id string) (Bundle, error) &i.Data, &i.Digest, &i.Signature, - &i.SigningCertificate, + &i.SigningCertificateChain, &i.CreatedAt, &i.UpdatedAt, ) @@ -84,7 +84,7 @@ func (q *Queries) FindBundleByID(ctx context.Context, id string) (Bundle, error) } const findBundleByTrustDomainID = `-- name: FindBundleByTrustDomainID :one -SELECT id, trust_domain_id, data, digest, signature, signing_certificate, created_at, updated_at +SELECT id, trust_domain_id, data, digest, signature, signing_certificate_chain, created_at, updated_at FROM bundles WHERE trust_domain_id = ? LIMIT 1 @@ -99,7 +99,7 @@ func (q *Queries) FindBundleByTrustDomainID(ctx context.Context, trustDomainID s &i.Data, &i.Digest, &i.Signature, - &i.SigningCertificate, + &i.SigningCertificateChain, &i.CreatedAt, &i.UpdatedAt, ) @@ -107,7 +107,7 @@ func (q *Queries) FindBundleByTrustDomainID(ctx context.Context, trustDomainID s } const listBundles = `-- name: ListBundles :many -SELECT id, trust_domain_id, data, digest, signature, signing_certificate, created_at, updated_at +SELECT id, trust_domain_id, data, digest, signature, signing_certificate_chain, created_at, updated_at FROM bundles ORDER BY created_at DESC ` @@ -127,7 +127,7 @@ func (q *Queries) ListBundles(ctx context.Context) ([]Bundle, error) { &i.Data, &i.Digest, &i.Signature, - &i.SigningCertificate, + &i.SigningCertificateChain, &i.CreatedAt, &i.UpdatedAt, ); err != nil { @@ -149,18 +149,18 @@ UPDATE bundles SET data = ?, digest = ?, signature = ?, - signing_certificate = ?, + signing_certificate_chain = ?, updated_at = datetime('now') WHERE id = ? -RETURNING id, trust_domain_id, data, digest, signature, signing_certificate, created_at, updated_at +RETURNING id, trust_domain_id, data, digest, signature, signing_certificate_chain, created_at, updated_at ` type UpdateBundleParams struct { - Data []byte - Digest []byte - Signature []byte - SigningCertificate []byte - ID string + Data []byte + Digest []byte + Signature []byte + SigningCertificateChain []byte + ID string } func (q *Queries) UpdateBundle(ctx context.Context, arg UpdateBundleParams) (Bundle, error) { @@ -168,7 +168,7 @@ func (q *Queries) UpdateBundle(ctx context.Context, arg UpdateBundleParams) (Bun arg.Data, arg.Digest, arg.Signature, - arg.SigningCertificate, + arg.SigningCertificateChain, arg.ID, ) var i Bundle @@ -178,7 +178,7 @@ func (q *Queries) UpdateBundle(ctx context.Context, arg UpdateBundleParams) (Bun &i.Data, &i.Digest, &i.Signature, - &i.SigningCertificate, + &i.SigningCertificateChain, &i.CreatedAt, &i.UpdatedAt, ) diff --git a/pkg/server/db/sqlite/datastore.go b/pkg/server/db/sqlite/datastore.go index cabba3ea..a63947a4 100644 --- a/pkg/server/db/sqlite/datastore.go +++ b/pkg/server/db/sqlite/datastore.go @@ -535,13 +535,13 @@ func (d *Datastore) updateRelationship(ctx context.Context, req *entity.Relation func (d *Datastore) createBundle(ctx context.Context, req *entity.Bundle) (*Bundle, error) { id := uuid.New() params := CreateBundleParams{ - ID: id.String(), - Data: req.Data, - Digest: req.Digest, - Signature: req.Signature, - SigningCertificate: req.SigningCertificate, - TrustDomainID: req.TrustDomainID.String(), - CreatedAt: req.CreatedAt, + ID: id.String(), + Data: req.Data, + Digest: req.Digest, + Signature: req.Signature, + SigningCertificateChain: req.SigningCertificateChain, + TrustDomainID: req.TrustDomainID.String(), + CreatedAt: req.CreatedAt, } bundle, err := d.querier.CreateBundle(ctx, params) @@ -554,11 +554,11 @@ func (d *Datastore) createBundle(ctx context.Context, req *entity.Bundle) (*Bund func (d *Datastore) updateBundle(ctx context.Context, req *entity.Bundle) (*Bundle, error) { params := UpdateBundleParams{ - ID: req.ID.UUID.String(), - Data: req.Data, - Digest: req.Digest, - Signature: req.Signature, - SigningCertificate: req.SigningCertificate, + ID: req.ID.UUID.String(), + Data: req.Data, + Digest: req.Digest, + Signature: req.Signature, + SigningCertificateChain: req.SigningCertificateChain, } bundle, err := d.querier.UpdateBundle(ctx, params) diff --git a/pkg/server/db/sqlite/helpers.go b/pkg/server/db/sqlite/helpers.go index 20aca63b..ec837de9 100644 --- a/pkg/server/db/sqlite/helpers.go +++ b/pkg/server/db/sqlite/helpers.go @@ -83,14 +83,14 @@ func (b Bundle) ToEntity() (*entity.Bundle, error) { } return &entity.Bundle{ - ID: nullID, - Data: b.Data, - Digest: b.Digest, - Signature: b.Signature, - SigningCertificate: b.SigningCertificate, - TrustDomainID: tdID, - CreatedAt: b.CreatedAt, - UpdatedAt: b.UpdatedAt, + ID: nullID, + Data: b.Data, + Digest: b.Digest, + Signature: b.Signature, + SigningCertificateChain: b.SigningCertificateChain, + TrustDomainID: tdID, + CreatedAt: b.CreatedAt, + UpdatedAt: b.UpdatedAt, }, nil } diff --git a/pkg/server/db/sqlite/migrations/1_initialize_schema.up.sql b/pkg/server/db/sqlite/migrations/1_initialize_schema.up.sql index 5a46f85e..09a8c42b 100644 --- a/pkg/server/db/sqlite/migrations/1_initialize_schema.up.sql +++ b/pkg/server/db/sqlite/migrations/1_initialize_schema.up.sql @@ -26,14 +26,14 @@ CREATE TABLE IF NOT EXISTS relationships CREATE TABLE IF NOT EXISTS bundles ( - id TEXT PRIMARY KEY, - trust_domain_id TEXT NOT NULL UNIQUE, - data BLOB NOT NULL, - digest BLOB NOT NULL, - signature BLOB, - signing_certificate BLOB, - created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + id TEXT PRIMARY KEY, + trust_domain_id TEXT NOT NULL UNIQUE, + data BLOB NOT NULL, + digest BLOB NOT NULL, + signature BLOB, + signing_certificate_chain BLOB, + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (trust_domain_id) REFERENCES trust_domains (id) ); diff --git a/pkg/server/db/sqlite/models.gen.go b/pkg/server/db/sqlite/models.gen.go index 05d01c4e..04687991 100644 --- a/pkg/server/db/sqlite/models.gen.go +++ b/pkg/server/db/sqlite/models.gen.go @@ -10,14 +10,14 @@ import ( ) type Bundle struct { - ID string - TrustDomainID string - Data []byte - Digest []byte - Signature []byte - SigningCertificate []byte - CreatedAt time.Time - UpdatedAt time.Time + ID string + TrustDomainID string + Data []byte + Digest []byte + Signature []byte + SigningCertificateChain []byte + CreatedAt time.Time + UpdatedAt time.Time } type JoinToken struct { diff --git a/pkg/server/db/sqlite/queries/bundles.sql b/pkg/server/db/sqlite/queries/bundles.sql index ae0068e4..4afa4320 100644 --- a/pkg/server/db/sqlite/queries/bundles.sql +++ b/pkg/server/db/sqlite/queries/bundles.sql @@ -1,5 +1,5 @@ -- name: CreateBundle :one -INSERT INTO bundles(id, data, digest, signature, signing_certificate, trust_domain_id, created_at) +INSERT INTO bundles(id, data, digest, signature, signing_certificate_chain, trust_domain_id, created_at) VALUES (?, ?, ?, ?, ?, ?, ?) RETURNING *; @@ -8,7 +8,7 @@ UPDATE bundles SET data = ?, digest = ?, signature = ?, - signing_certificate = ?, + signing_certificate_chain = ?, updated_at = datetime('now') WHERE id = ? RETURNING *; diff --git a/pkg/server/db/tests/datastore_test.go b/pkg/server/db/tests/datastore_test.go index a1bf2dea..6744b378 100644 --- a/pkg/server/db/tests/datastore_test.go +++ b/pkg/server/db/tests/datastore_test.go @@ -281,12 +281,12 @@ func runDatastoreTests(t *testing.T, ctx context.Context, newDS func(*testing.T) // Create first Data - trustDomain-1 req1 := &entity.Bundle{ - Data: []byte{1, 2, 3}, - Digest: []byte("test-digest"), - Signature: []byte{4, 2}, - SigningCertificate: []byte{50, 60}, - TrustDomainID: td1.ID.UUID, - CreatedAt: inFiveSeconds, + Data: []byte{1, 2, 3}, + Digest: []byte("test-digest"), + Signature: []byte{4, 2}, + SigningCertificateChain: []byte{50, 60}, + TrustDomainID: td1.ID.UUID, + CreatedAt: inFiveSeconds, } b1, err := ds.CreateOrUpdateBundle(ctx, req1) @@ -295,7 +295,7 @@ func runDatastoreTests(t *testing.T, ctx context.Context, newDS func(*testing.T) assert.Equal(t, req1.Data, b1.Data) assert.Equal(t, req1.Digest, b1.Digest) assert.Equal(t, req1.Signature, b1.Signature) - assert.Equal(t, req1.SigningCertificate, b1.SigningCertificate) + assert.Equal(t, req1.SigningCertificateChain, b1.SigningCertificateChain) assert.Equal(t, req1.TrustDomainID, b1.TrustDomainID) assert.Equal(t, req1.CreatedAt, b1.CreatedAt.In(location)) @@ -306,11 +306,11 @@ func runDatastoreTests(t *testing.T, ctx context.Context, newDS func(*testing.T) // Create second Data -> trustDomain-2 req2 := &entity.Bundle{ - Data: []byte{10, 20, 30}, - Digest: []byte("test-digest-2"), - Signature: []byte{40, 20}, - SigningCertificate: []byte{80, 90}, - TrustDomainID: td2.ID.UUID, + Data: []byte{10, 20, 30}, + Digest: []byte("test-digest-2"), + Signature: []byte{40, 20}, + SigningCertificateChain: []byte{80, 90}, + TrustDomainID: td2.ID.UUID, } b2, err := ds.CreateOrUpdateBundle(ctx, req2) @@ -319,7 +319,7 @@ func runDatastoreTests(t *testing.T, ctx context.Context, newDS func(*testing.T) assert.Equal(t, req2.Data, b2.Data) assert.Equal(t, req2.Digest, b2.Digest) assert.Equal(t, req2.Signature, b2.Signature) - assert.Equal(t, req2.SigningCertificate, b2.SigningCertificate) + assert.Equal(t, req2.SigningCertificateChain, b2.SigningCertificateChain) assert.Equal(t, req2.TrustDomainID, b2.TrustDomainID) // Look up bundle stored in DB and compare @@ -340,7 +340,7 @@ func runDatastoreTests(t *testing.T, ctx context.Context, newDS func(*testing.T) b1.Data = []byte{'a', 'b', 'c'} b1.Digest = []byte("test-digest-3") b1.Signature = []byte{'f', 'g', 'h'} - b1.SigningCertificate = []byte{'f', 'g', 'h'} + b1.SigningCertificateChain = []byte{'f', 'g', 'h'} updated, err := ds.CreateOrUpdateBundle(ctx, b1) assert.NoError(t, err) @@ -348,7 +348,7 @@ func runDatastoreTests(t *testing.T, ctx context.Context, newDS func(*testing.T) assert.Equal(t, b1.Data, updated.Data) assert.Equal(t, b1.Digest, updated.Digest) assert.Equal(t, b1.Signature, updated.Signature) - assert.Equal(t, b1.SigningCertificate, updated.SigningCertificate) + assert.Equal(t, b1.SigningCertificateChain, updated.SigningCertificateChain) assert.Equal(t, b1.TrustDomainID, updated.TrustDomainID) // Look up bundle stored in DB and compare @@ -393,11 +393,11 @@ func runDatastoreTests(t *testing.T, ctx context.Context, newDS func(*testing.T) // Create Data b1 := &entity.Bundle{ - Data: []byte{1, 2, 3}, - Digest: []byte("test-digest-1"), - Signature: []byte{4, 2}, - SigningCertificate: []byte{50, 60}, - TrustDomainID: td1.ID.UUID, + Data: []byte{1, 2, 3}, + Digest: []byte("test-digest-1"), + Signature: []byte{4, 2}, + SigningCertificateChain: []byte{50, 60}, + TrustDomainID: td1.ID.UUID, } b1, err := ds.CreateOrUpdateBundle(ctx, b1) assert.NoError(t, err) @@ -405,11 +405,11 @@ func runDatastoreTests(t *testing.T, ctx context.Context, newDS func(*testing.T) // Create second Data associated to same trustDomain b2 := &entity.Bundle{ - Data: []byte{10, 20, 30}, - Digest: []byte("test-digest-2"), - Signature: []byte{40, 20}, - SigningCertificate: []byte{80, 90}, - TrustDomainID: td1.ID.UUID, + Data: []byte{10, 20, 30}, + Digest: []byte("test-digest-2"), + Signature: []byte{40, 20}, + SigningCertificateChain: []byte{80, 90}, + TrustDomainID: td1.ID.UUID, } b2, err = ds.CreateOrUpdateBundle(ctx, b2) require.Error(t, err) diff --git a/pkg/server/endpoints/harvester.go b/pkg/server/endpoints/harvester.go index 608c5519..7d8e3fa4 100644 --- a/pkg/server/endpoints/harvester.go +++ b/pkg/server/endpoints/harvester.go @@ -459,7 +459,7 @@ func (h *HarvesterAPIHandlers) getBundleSyncResult(ctx context.Context, authTD * updateItem.TrustBundle = string(bundle.Data) updateItem.Digest = encoding.EncodeToBase64(bundle.Digest[:]) updateItem.Signature = encoding.EncodeToBase64(bundle.Signature) - updateItem.SigningCertificate = encoding.EncodeToBase64(bundle.SigningCertificate) + updateItem.SigningCertificateChain = encoding.EncodeToBase64(bundle.SigningCertificateChain) resp.Updates[bundle.TrustDomainName.String()] = updateItem } diff --git a/pkg/server/endpoints/harvester_test.go b/pkg/server/endpoints/harvester_test.go index 96c67b91..806ea06a 100644 --- a/pkg/server/endpoints/harvester_test.go +++ b/pkg/server/endpoints/harvester_test.go @@ -605,10 +605,10 @@ func TestBundlePut(t *testing.T) { sig := "test-signature" cert := "test-certificate" bundlePut := harvester.PutBundleRequest{ - Signature: &sig, - SigningCertificate: &cert, - TrustBundle: "a new bundle", - TrustDomain: td1, + Signature: &sig, + SigningCertificateChain: &cert, + TrustBundle: "a new bundle", + TrustDomain: td1, } setup := NewHarvesterTestSetup(t, http.MethodPut, "/trust-domain/:trustDomainName/bundles", &bundlePut) @@ -639,11 +639,11 @@ func testBundlePut(t *testing.T, setupFunc func(*HarvesterTestSetup) *entity.Tru sig := encoding.EncodeToBase64([]byte("test-signature")) cert := encoding.EncodeToBase64([]byte("test-signing-certificate")) bundlePut := harvester.PutBundleRequest{ - Signature: &sig, - SigningCertificate: &cert, - TrustBundle: bundle, - Digest: digest, - TrustDomain: td1, + Signature: &sig, + SigningCertificateChain: &cert, + TrustBundle: bundle, + Digest: digest, + TrustDomain: td1, } setup := NewHarvesterTestSetup(t, http.MethodPut, "/trust-domain/:trustDomainName/bundles", &bundlePut) @@ -663,7 +663,7 @@ func testBundlePut(t *testing.T, setupFunc func(*HarvesterTestSetup) *entity.Tru assert.Equal(t, bundlePut.TrustBundle, string(storedBundle.Data)) assert.Equal(t, digest, encoding.EncodeToBase64(storedBundle.Digest)) assert.Equal(t, sig, encoding.EncodeToBase64(storedBundle.Signature)) - assert.Equal(t, cert, encoding.EncodeToBase64(storedBundle.SigningCertificate)) + assert.Equal(t, cert, encoding.EncodeToBase64(storedBundle.SigningCertificateChain)) assert.Equal(t, td.ID.UUID, storedBundle.TrustDomainID) } @@ -673,11 +673,11 @@ func testInvalidBundleRequest(t *testing.T, fieldName string, fieldValue interfa bundle := "test trust bundle" digest := encoding.EncodeToBase64(cryptoutil.CalculateDigest([]byte(bundle))) bundlePut := harvester.PutBundleRequest{ - Signature: &sig, - SigningCertificate: &cert, - TrustBundle: bundle, - Digest: digest, - TrustDomain: td1, + Signature: &sig, + SigningCertificateChain: &cert, + TrustBundle: bundle, + Digest: digest, + TrustDomain: td1, } reflect.ValueOf(&bundlePut).Elem().FieldByName(fieldName).Set(reflect.ValueOf(fieldValue)) From 3d68af9a0ecf4723bbedd4550a68d1334ad968f2 Mon Sep 17 00:00:00 2001 From: Max Lambrecht Date: Thu, 13 Jul 2023 10:08:33 -0500 Subject: [PATCH 2/3] Address PR comments Signed-off-by: Max Lambrecht --- pkg/harvester/catalog/catalog_test.go | 2 +- pkg/harvester/integrity/disk.go | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/pkg/harvester/catalog/catalog_test.go b/pkg/harvester/catalog/catalog_test.go index 53e32548..7d52e14b 100644 --- a/pkg/harvester/catalog/catalog_test.go +++ b/pkg/harvester/catalog/catalog_test.go @@ -23,7 +23,7 @@ providers { signing_cert_ttl = "%s" } BundleVerifier "disk" { - trust_bundle_path = "%s" + trust_bundle_path = "%s" } BundleVerifier "noop" { } diff --git a/pkg/harvester/integrity/disk.go b/pkg/harvester/integrity/disk.go index fecf661c..71efa57e 100644 --- a/pkg/harvester/integrity/disk.go +++ b/pkg/harvester/integrity/disk.go @@ -217,8 +217,9 @@ func (v *DiskVerifier) Verify(payload, signature []byte, signingCertificateChain return fmt.Errorf("failed to verify signing certificate chain: %w", err) } - // verifies signature of payload - if err := rsa.VerifyPKCS1v15(signingCertificateChain[0].PublicKey.(*rsa.PublicKey), crypto.SHA256, hashed[:], signature); err != nil { + // Verify the signature of the payload + publicKey := signingCertificateChain[0].PublicKey.(*rsa.PublicKey) + if err := rsa.VerifyPKCS1v15(publicKey, crypto.SHA256, hashed[:], signature); err != nil { return ErrInvalidSignature } From a5e376a612174bf80a151d90e786017e8201c46c Mon Sep 17 00:00:00 2001 From: Max Lambrecht Date: Thu, 13 Jul 2023 10:10:55 -0500 Subject: [PATCH 3/3] Address PR comments Signed-off-by: Max Lambrecht --- pkg/harvester/catalog/catalog_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/harvester/catalog/catalog_test.go b/pkg/harvester/catalog/catalog_test.go index 7d52e14b..6c63df29 100644 --- a/pkg/harvester/catalog/catalog_test.go +++ b/pkg/harvester/catalog/catalog_test.go @@ -17,9 +17,9 @@ import ( var hclConfigTemplate = ` providers { BundleSigner "disk" { - ca_cert_path = "%s" + ca_cert_path = "%s" ca_private_key_path = "%s" - trust_bundle_path = "%s" + trust_bundle_path = "%s" signing_cert_ttl = "%s" } BundleVerifier "disk" {