test: add unit tests for pkg/tlsutil
This commit is contained in:
parent
35412b63d8
commit
b1fba8e76c
1 changed files with 318 additions and 0 deletions
318
pkg/tlsutil/tlsutil_test.go
Normal file
318
pkg/tlsutil/tlsutil_test.go
Normal file
|
|
@ -0,0 +1,318 @@
|
|||
package tlsutil
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/hex"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestFingerprintVerifier_NormalizesFingerprint(t *testing.T) {
|
||||
// Fingerprint with colons
|
||||
fp1 := "AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99"
|
||||
// Same fingerprint without colons, lowercase
|
||||
fp2 := "aabbccddeeff00112233445566778899aabbccddeeff00112233445566778899"
|
||||
|
||||
config1 := FingerprintVerifier(fp1)
|
||||
config2 := FingerprintVerifier(fp2)
|
||||
|
||||
// Both should have InsecureSkipVerify set (we do our own verification)
|
||||
if !config1.InsecureSkipVerify {
|
||||
t.Error("FingerprintVerifier should set InsecureSkipVerify to true")
|
||||
}
|
||||
if !config2.InsecureSkipVerify {
|
||||
t.Error("FingerprintVerifier should set InsecureSkipVerify to true")
|
||||
}
|
||||
|
||||
// Both should have VerifyPeerCertificate function set
|
||||
if config1.VerifyPeerCertificate == nil {
|
||||
t.Error("FingerprintVerifier should set VerifyPeerCertificate")
|
||||
}
|
||||
if config2.VerifyPeerCertificate == nil {
|
||||
t.Error("FingerprintVerifier should set VerifyPeerCertificate")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFingerprintVerifier_NoCertificates(t *testing.T) {
|
||||
config := FingerprintVerifier("aabbccdd")
|
||||
|
||||
// Should fail when no certificates presented
|
||||
err := config.VerifyPeerCertificate([][]byte{}, nil)
|
||||
if err == nil {
|
||||
t.Error("Should fail when no certificates presented")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "no certificates") {
|
||||
t.Errorf("Error message should mention no certificates, got: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFingerprintVerifier_MatchingFingerprint(t *testing.T) {
|
||||
// Create a mock certificate (just random bytes for testing)
|
||||
mockCert := []byte("mock certificate data for testing purposes")
|
||||
|
||||
// Calculate its fingerprint
|
||||
fingerprint := sha256.Sum256(mockCert)
|
||||
expectedFP := hex.EncodeToString(fingerprint[:])
|
||||
|
||||
config := FingerprintVerifier(expectedFP)
|
||||
|
||||
// Should succeed with matching fingerprint
|
||||
err := config.VerifyPeerCertificate([][]byte{mockCert}, nil)
|
||||
if err != nil {
|
||||
t.Errorf("Should succeed with matching fingerprint, got: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFingerprintVerifier_MismatchedFingerprint(t *testing.T) {
|
||||
mockCert := []byte("mock certificate data")
|
||||
|
||||
// Use a different fingerprint
|
||||
wrongFP := "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
|
||||
config := FingerprintVerifier(wrongFP)
|
||||
|
||||
// Should fail with mismatched fingerprint
|
||||
err := config.VerifyPeerCertificate([][]byte{mockCert}, nil)
|
||||
if err == nil {
|
||||
t.Error("Should fail with mismatched fingerprint")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "mismatch") {
|
||||
t.Errorf("Error message should mention mismatch, got: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateHTTPClient_InsecureMode(t *testing.T) {
|
||||
client := CreateHTTPClient(false, "")
|
||||
|
||||
if client == nil {
|
||||
t.Fatal("CreateHTTPClient returned nil")
|
||||
}
|
||||
|
||||
transport, ok := client.Transport.(*http.Transport)
|
||||
if !ok {
|
||||
t.Fatal("Transport is not *http.Transport")
|
||||
}
|
||||
|
||||
if transport.TLSClientConfig == nil {
|
||||
t.Fatal("TLSClientConfig should be set")
|
||||
}
|
||||
|
||||
if !transport.TLSClientConfig.InsecureSkipVerify {
|
||||
t.Error("InsecureSkipVerify should be true in insecure mode")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateHTTPClient_FingerprintMode(t *testing.T) {
|
||||
fingerprint := "aabbccdd"
|
||||
client := CreateHTTPClient(false, fingerprint)
|
||||
|
||||
if client == nil {
|
||||
t.Fatal("CreateHTTPClient returned nil")
|
||||
}
|
||||
|
||||
transport, ok := client.Transport.(*http.Transport)
|
||||
if !ok {
|
||||
t.Fatal("Transport is not *http.Transport")
|
||||
}
|
||||
|
||||
if transport.TLSClientConfig == nil {
|
||||
t.Fatal("TLSClientConfig should be set")
|
||||
}
|
||||
|
||||
// Should have custom verification function
|
||||
if transport.TLSClientConfig.VerifyPeerCertificate == nil {
|
||||
t.Error("VerifyPeerCertificate should be set in fingerprint mode")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateHTTPClient_SecureMode(t *testing.T) {
|
||||
client := CreateHTTPClient(true, "")
|
||||
|
||||
if client == nil {
|
||||
t.Fatal("CreateHTTPClient returned nil")
|
||||
}
|
||||
|
||||
transport, ok := client.Transport.(*http.Transport)
|
||||
if !ok {
|
||||
t.Fatal("Transport is not *http.Transport")
|
||||
}
|
||||
|
||||
// In secure mode, TLSClientConfig should either be nil (use defaults)
|
||||
// or not have InsecureSkipVerify set
|
||||
if transport.TLSClientConfig != nil && transport.TLSClientConfig.InsecureSkipVerify {
|
||||
t.Error("InsecureSkipVerify should not be true in secure mode")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateHTTPClientWithTimeout_DefaultTimeout(t *testing.T) {
|
||||
client := CreateHTTPClientWithTimeout(true, "", 0)
|
||||
|
||||
if client == nil {
|
||||
t.Fatal("CreateHTTPClientWithTimeout returned nil")
|
||||
}
|
||||
|
||||
// Should use default timeout when 0 is passed
|
||||
if client.Timeout != 60*time.Second {
|
||||
t.Errorf("Timeout = %v, want %v", client.Timeout, 60*time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateHTTPClientWithTimeout_CustomTimeout(t *testing.T) {
|
||||
customTimeout := 30 * time.Second
|
||||
client := CreateHTTPClientWithTimeout(true, "", customTimeout)
|
||||
|
||||
if client == nil {
|
||||
t.Fatal("CreateHTTPClientWithTimeout returned nil")
|
||||
}
|
||||
|
||||
if client.Timeout != customTimeout {
|
||||
t.Errorf("Timeout = %v, want %v", client.Timeout, customTimeout)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateHTTPClientWithTimeout_NegativeTimeout(t *testing.T) {
|
||||
client := CreateHTTPClientWithTimeout(true, "", -10*time.Second)
|
||||
|
||||
if client == nil {
|
||||
t.Fatal("CreateHTTPClientWithTimeout returned nil")
|
||||
}
|
||||
|
||||
// Should use default timeout when negative is passed
|
||||
if client.Timeout != 60*time.Second {
|
||||
t.Errorf("Timeout = %v, want %v (default)", client.Timeout, 60*time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateHTTPClient_TransportSettings(t *testing.T) {
|
||||
client := CreateHTTPClient(true, "")
|
||||
|
||||
transport, ok := client.Transport.(*http.Transport)
|
||||
if !ok {
|
||||
t.Fatal("Transport is not *http.Transport")
|
||||
}
|
||||
|
||||
// Verify transport settings
|
||||
if transport.MaxIdleConns != 100 {
|
||||
t.Errorf("MaxIdleConns = %v, want 100", transport.MaxIdleConns)
|
||||
}
|
||||
if transport.MaxIdleConnsPerHost != 20 {
|
||||
t.Errorf("MaxIdleConnsPerHost = %v, want 20", transport.MaxIdleConnsPerHost)
|
||||
}
|
||||
if transport.MaxConnsPerHost != 20 {
|
||||
t.Errorf("MaxConnsPerHost = %v, want 20", transport.MaxConnsPerHost)
|
||||
}
|
||||
if transport.IdleConnTimeout != 90*time.Second {
|
||||
t.Errorf("IdleConnTimeout = %v, want 90s", transport.IdleConnTimeout)
|
||||
}
|
||||
if !transport.DisableCompression {
|
||||
t.Error("DisableCompression should be true")
|
||||
}
|
||||
if transport.TLSHandshakeTimeout != 10*time.Second {
|
||||
t.Errorf("TLSHandshakeTimeout = %v, want 10s", transport.TLSHandshakeTimeout)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFingerprintVerifier_IgnoresVerifiedChains(t *testing.T) {
|
||||
mockCert := []byte("test certificate")
|
||||
fingerprint := sha256.Sum256(mockCert)
|
||||
expectedFP := hex.EncodeToString(fingerprint[:])
|
||||
|
||||
config := FingerprintVerifier(expectedFP)
|
||||
|
||||
// verifiedChains parameter should be ignored
|
||||
mockChains := [][]*x509.Certificate{{&x509.Certificate{}}}
|
||||
err := config.VerifyPeerCertificate([][]byte{mockCert}, mockChains)
|
||||
if err != nil {
|
||||
t.Errorf("Should ignore verifiedChains, got error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetDNSResolver(t *testing.T) {
|
||||
resolver := GetDNSResolver()
|
||||
|
||||
if resolver == nil {
|
||||
t.Fatal("GetDNSResolver returned nil")
|
||||
}
|
||||
|
||||
// Call again - should return same instance (singleton)
|
||||
resolver2 := GetDNSResolver()
|
||||
if resolver != resolver2 {
|
||||
t.Error("GetDNSResolver should return same instance")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetDNSCacheTTL_DefaultValue(t *testing.T) {
|
||||
// Setting TTL to 0 should use default
|
||||
SetDNSCacheTTL(0)
|
||||
// No panic means success - we can't easily verify the internal state
|
||||
}
|
||||
|
||||
func TestSetDNSCacheTTL_NegativeValue(t *testing.T) {
|
||||
// Setting TTL to negative should use default
|
||||
SetDNSCacheTTL(-5 * time.Minute)
|
||||
// No panic means success
|
||||
}
|
||||
|
||||
func TestSetDNSCacheTTL_CustomValue(t *testing.T) {
|
||||
// Setting custom TTL
|
||||
SetDNSCacheTTL(10 * time.Minute)
|
||||
// No panic means success
|
||||
}
|
||||
|
||||
func TestFingerprintVerifier_ColonSeparatedFingerprint(t *testing.T) {
|
||||
mockCert := []byte("test cert with colons")
|
||||
fingerprint := sha256.Sum256(mockCert)
|
||||
|
||||
// Format with colons (common format from openssl)
|
||||
fpBytes := fingerprint[:]
|
||||
var parts []string
|
||||
for _, b := range fpBytes {
|
||||
parts = append(parts, hex.EncodeToString([]byte{b}))
|
||||
}
|
||||
colonSeparated := strings.ToUpper(strings.Join(parts, ":"))
|
||||
|
||||
config := FingerprintVerifier(colonSeparated)
|
||||
|
||||
err := config.VerifyPeerCertificate([][]byte{mockCert}, nil)
|
||||
if err != nil {
|
||||
t.Errorf("Should handle colon-separated fingerprint, got: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateHTTPClient_FingerprintTakesPrecedence(t *testing.T) {
|
||||
// Even if verifySSL is true, fingerprint mode should be used if fingerprint is provided
|
||||
fingerprint := "aabbccdd"
|
||||
client := CreateHTTPClient(true, fingerprint)
|
||||
|
||||
transport, ok := client.Transport.(*http.Transport)
|
||||
if !ok {
|
||||
t.Fatal("Transport is not *http.Transport")
|
||||
}
|
||||
|
||||
// Should use fingerprint verification
|
||||
if transport.TLSClientConfig == nil {
|
||||
t.Fatal("TLSClientConfig should be set")
|
||||
}
|
||||
if transport.TLSClientConfig.VerifyPeerCertificate == nil {
|
||||
t.Error("Should use fingerprint verification when fingerprint is provided")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFingerprintVerifier_TLSVersion(t *testing.T) {
|
||||
config := FingerprintVerifier("aabbccdd")
|
||||
|
||||
// Check that config is a valid TLS config
|
||||
if config == nil {
|
||||
t.Fatal("FingerprintVerifier returned nil config")
|
||||
}
|
||||
|
||||
// MinVersion should not be set to an insecure version
|
||||
// (default is fine, or TLS 1.2+)
|
||||
if config.MinVersion != 0 && config.MinVersion < tls.VersionTLS12 {
|
||||
t.Errorf("MinVersion should be 0 (default) or >= TLS 1.2, got %v", config.MinVersion)
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue