package config import ( "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "crypto/x509" "crypto/x509/pkix" "encoding/base64" "encoding/pem" "math/big" "os" "testing" "time" "github.com/stretchr/testify/require" ) func newCACertPEM() ([]byte, error) { key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { return nil, err } tpl := &x509.Certificate{ SerialNumber: big.NewInt(time.Now().Unix()), Subject: pkix.Name{ CommonName: "Test CA", }, NotBefore: time.Now(), NotAfter: time.Now().Add(time.Minute * 10), KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageDigitalSignature, BasicConstraintsValid: true, IsCA: true, } der, err := x509.CreateCertificate(rand.Reader, tpl, tpl, &key.PublicKey, key) if err != nil { return nil, err } return pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: der}), nil } func TestAutocertOptions_Validate(t *testing.T) { certPEM, err := newCACertPEM() require.NoError(t, err) type fields struct { Enable bool CA string Email string UseStaging bool EABKeyID string EABMACKey string MustStaple bool Folder string TrustedCA string TrustedCAFile string } type test struct { fields fields wantErr bool cleanup func() } tests := map[string]func(t *testing.T) test{ "ok/custom-ca": func(_ *testing.T) test { return test{ fields: fields{ CA: "test-ca.example.com/directory", }, wantErr: false, } }, "ok/eab": func(_ *testing.T) test { return test{ fields: fields{ EABKeyID: "keyID", EABMACKey: "29D7t6-mOuEV5vvBRX0UYF5T7x6fomidhM1kMJco-yw", }, wantErr: false, } }, "ok/trusted-ca": func(_ *testing.T) test { return test{ fields: fields{ TrustedCA: base64.StdEncoding.EncodeToString(certPEM), }, wantErr: false, } }, "ok/trusted-ca-file": func(t *testing.T) test { f, err := os.CreateTemp("", "pomerium-test-ca") require.NoError(t, err) n, err := f.Write(certPEM) require.NoError(t, err) require.Equal(t, len(certPEM), n) return test{ fields: fields{ TrustedCAFile: f.Name(), }, wantErr: false, cleanup: func() { os.Remove(f.Name()) }, } }, "fail/missing-eab-key": func(_ *testing.T) test { return test{ fields: fields{ EABKeyID: "keyID", }, wantErr: true, } }, "fail/missing-eab-key-id": func(_ *testing.T) test { return test{ fields: fields{ EABMACKey: "29D7t6-mOuEV5vvBRX0UYF5T7x6fomidhM1kMJco-yw", }, wantErr: true, } }, "fail/invalid-mac-key": func(_ *testing.T) test { return test{ fields: fields{ EABMACKey: ">invalid-base64-url-encoded-mac-key<", }, wantErr: true, } }, "fail/trusted-ca-combined": func(t *testing.T) test { f, err := os.CreateTemp("", "pomerium-test-ca") require.NoError(t, err) n, err := f.Write(certPEM) require.NoError(t, err) require.Equal(t, len(certPEM), n) return test{ fields: fields{ TrustedCA: base64.StdEncoding.EncodeToString(certPEM), TrustedCAFile: f.Name(), }, wantErr: true, cleanup: func() { os.Remove(f.Name()) }, } }, "fail/trusted-ca-invalid-base64-pem": func(_ *testing.T) test { return test{ fields: fields{ TrustedCA: ">invalid-base-64-data<", }, wantErr: true, } }, "fail/trusted-ca-missing-file": func(_ *testing.T) test { return test{ fields: fields{ TrustedCAFile: "some-non-existing-file", }, wantErr: true, } }, } for name, run := range tests { tc := run(t) t.Run(name, func(t *testing.T) { o := &AutocertOptions{ Enable: tc.fields.Enable, CA: tc.fields.CA, Email: tc.fields.Email, UseStaging: tc.fields.UseStaging, EABKeyID: tc.fields.EABKeyID, EABMACKey: tc.fields.EABMACKey, MustStaple: tc.fields.MustStaple, Folder: tc.fields.Folder, TrustedCA: tc.fields.TrustedCA, TrustedCAFile: tc.fields.TrustedCAFile, } if err := o.Validate(); (err != nil) != tc.wantErr { t.Errorf("AutocertOptions.Validate() error = %v, wantErr %v", err, tc.wantErr) } if tc.cleanup != nil { tc.cleanup() } }) } }