github.com/letsencrypt/boulder@v0.20251208.0/cmd/config_test.go (about)

     1  package cmd
     2  
     3  import (
     4  	"crypto/ecdsa"
     5  	"crypto/elliptic"
     6  	"crypto/rand"
     7  	"crypto/x509"
     8  	"crypto/x509/pkix"
     9  	"encoding/pem"
    10  	"math/big"
    11  	"os"
    12  	"path"
    13  	"regexp"
    14  	"strings"
    15  	"testing"
    16  	"time"
    17  
    18  	"github.com/letsencrypt/boulder/metrics"
    19  	"github.com/letsencrypt/boulder/test"
    20  )
    21  
    22  func TestDBConfigURL(t *testing.T) {
    23  	tests := []struct {
    24  		conf     DBConfig
    25  		expected string
    26  	}{
    27  		{
    28  			// Test with one config file that has no trailing newline
    29  			conf:     DBConfig{DBConnectFile: "testdata/test_dburl"},
    30  			expected: "test@tcp(testhost:3306)/testDB?readTimeout=800ms&writeTimeout=800ms",
    31  		},
    32  		{
    33  			// Test with a config file that *has* a trailing newline
    34  			conf:     DBConfig{DBConnectFile: "testdata/test_dburl_newline"},
    35  			expected: "test@tcp(testhost:3306)/testDB?readTimeout=800ms&writeTimeout=800ms",
    36  		},
    37  	}
    38  
    39  	for _, tc := range tests {
    40  		url, err := tc.conf.URL()
    41  		test.AssertNotError(t, err, "Failed calling URL() on DBConfig")
    42  		test.AssertEquals(t, url, tc.expected)
    43  	}
    44  }
    45  
    46  func TestPasswordConfig(t *testing.T) {
    47  	tests := []struct {
    48  		pc       PasswordConfig
    49  		expected string
    50  	}{
    51  		{pc: PasswordConfig{}, expected: ""},
    52  		{pc: PasswordConfig{PasswordFile: "testdata/test_secret"}, expected: "secret"},
    53  	}
    54  
    55  	for _, tc := range tests {
    56  		password, err := tc.pc.Pass()
    57  		test.AssertNotError(t, err, "Failed to retrieve password")
    58  		test.AssertEquals(t, password, tc.expected)
    59  	}
    60  }
    61  
    62  func TestTLSConfigLoad(t *testing.T) {
    63  	null := "/dev/null"
    64  	nonExistent := "[nonexistent]"
    65  	tmp := t.TempDir()
    66  	cert := path.Join(tmp, "TestTLSConfigLoad.cert.pem")
    67  	key := path.Join(tmp, "TestTLSConfigLoad.key.pem")
    68  	caCert := path.Join(tmp, "TestTLSConfigLoad.cacert.pem")
    69  
    70  	rootKey, err := ecdsa.GenerateKey(elliptic.P224(), rand.Reader)
    71  	test.AssertNotError(t, err, "creating test root key")
    72  	rootTemplate := &x509.Certificate{
    73  		Subject:      pkix.Name{CommonName: "test root"},
    74  		SerialNumber: big.NewInt(12345),
    75  		NotBefore:    time.Now().Add(-24 * time.Hour),
    76  		NotAfter:     time.Now().Add(24 * time.Hour),
    77  		IsCA:         true,
    78  	}
    79  	rootCert, err := x509.CreateCertificate(rand.Reader, rootTemplate, rootTemplate, rootKey.Public(), rootKey)
    80  	test.AssertNotError(t, err, "creating test root cert")
    81  	err = os.WriteFile(caCert, pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: rootCert}), os.ModeAppend)
    82  	test.AssertNotError(t, err, "writing test root cert to disk")
    83  
    84  	intKey, err := ecdsa.GenerateKey(elliptic.P224(), rand.Reader)
    85  	test.AssertNotError(t, err, "creating test intermediate key")
    86  	intKeyBytes, err := x509.MarshalECPrivateKey(intKey)
    87  	test.AssertNotError(t, err, "marshalling test intermediate key")
    88  	err = os.WriteFile(key, pem.EncodeToMemory(&pem.Block{Type: "EC PRIVATE KEY", Bytes: intKeyBytes}), os.ModeAppend)
    89  	test.AssertNotError(t, err, "writing test intermediate key cert to disk")
    90  
    91  	intTemplate := &x509.Certificate{
    92  		Subject:      pkix.Name{CommonName: "test intermediate"},
    93  		SerialNumber: big.NewInt(67890),
    94  		NotBefore:    time.Now().Add(-12 * time.Hour),
    95  		NotAfter:     time.Now().Add(12 * time.Hour),
    96  		IsCA:         true,
    97  	}
    98  	intCert, err := x509.CreateCertificate(rand.Reader, intTemplate, rootTemplate, intKey.Public(), rootKey)
    99  	test.AssertNotError(t, err, "creating test intermediate cert")
   100  	err = os.WriteFile(cert, pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: intCert}), os.ModeAppend)
   101  	test.AssertNotError(t, err, "writing test intermediate cert to disk")
   102  
   103  	testCases := []struct {
   104  		TLSConfig
   105  		want string
   106  	}{
   107  		{TLSConfig{"", null, null}, "nil CertFile in TLSConfig"},
   108  		{TLSConfig{null, "", null}, "nil KeyFile in TLSConfig"},
   109  		{TLSConfig{null, null, ""}, "nil CACertFile in TLSConfig"},
   110  		{TLSConfig{nonExistent, key, caCert}, "loading key pair.*no such file or directory"},
   111  		{TLSConfig{cert, nonExistent, caCert}, "loading key pair.*no such file or directory"},
   112  		{TLSConfig{cert, key, nonExistent}, "reading CA cert from.*no such file or directory"},
   113  		{TLSConfig{null, key, caCert}, "loading key pair.*failed to find any PEM data"},
   114  		{TLSConfig{cert, null, caCert}, "loading key pair.*failed to find any PEM data"},
   115  		{TLSConfig{cert, key, null}, "parsing CA certs"},
   116  		{TLSConfig{cert, key, caCert}, ""},
   117  	}
   118  	for _, tc := range testCases {
   119  		title := [3]string{tc.CertFile, tc.KeyFile, tc.CACertFile}
   120  		for i := range title {
   121  			if title[i] == "" {
   122  				title[i] = "nil"
   123  			}
   124  		}
   125  		t.Run(strings.Join(title[:], "_"), func(t *testing.T) {
   126  			_, err := tc.TLSConfig.Load(metrics.NoopRegisterer)
   127  			if err == nil && tc.want == "" {
   128  				return
   129  			}
   130  			if err == nil {
   131  				t.Errorf("got no error")
   132  			}
   133  			if matched, _ := regexp.MatchString(tc.want, err.Error()); !matched {
   134  				t.Errorf("got error %q, wanted %q", err, tc.want)
   135  			}
   136  		})
   137  	}
   138  }
   139  
   140  func TestHMACKeyConfigLoad(t *testing.T) {
   141  	t.Parallel()
   142  
   143  	tests := []struct {
   144  		name        string
   145  		content     string
   146  		expectedErr bool
   147  	}{
   148  		{
   149  			name:        "Valid key",
   150  			content:     "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
   151  			expectedErr: false,
   152  		},
   153  		{
   154  			name:        "Empty file",
   155  			content:     "",
   156  			expectedErr: true,
   157  		},
   158  		{
   159  			name:        "Just under 256-bit",
   160  			content:     "0123456789abcdef0123456789abcdef0123456789abcdef0123456789ab",
   161  			expectedErr: true,
   162  		},
   163  		{
   164  			name:        "Just over 256-bit",
   165  			content:     "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef01",
   166  			expectedErr: true,
   167  		},
   168  	}
   169  
   170  	for _, tt := range tests {
   171  		t.Run(tt.name, func(t *testing.T) {
   172  			t.Parallel()
   173  
   174  			tempKeyFile, err := os.CreateTemp("", "*")
   175  			if err != nil {
   176  				t.Fatalf("failed to create temp file: %v", err)
   177  			}
   178  			defer os.Remove(tempKeyFile.Name())
   179  
   180  			_, err = tempKeyFile.WriteString(tt.content)
   181  			if err != nil {
   182  				t.Fatalf("failed to write to temp file: %v", err)
   183  			}
   184  			tempKeyFile.Close()
   185  
   186  			hmacKeyConfig := HMACKeyConfig{KeyFile: tempKeyFile.Name()}
   187  			_, err = hmacKeyConfig.Load()
   188  			if (err != nil) != tt.expectedErr {
   189  				t.Errorf("expected error: %v, got: %v", tt.expectedErr, err)
   190  			}
   191  		})
   192  	}
   193  }