mirror of
https://github.com/gesellix/Bose-SoundTouch.git
synced 2026-08-20 17:46:19 +00:00
- Add RFC-compliant wildcard certificates (*.api.bose.io, *.api.bosecm.com) for automatic API coverage - Include additional Bose production domains (worldwide.bose.com, music.api.bose.com, bose-prod.apigee.net) - Implement TLS certificate request logging and wildcard domain matching logic - Add detailed TLS handshake debugging with connection state tracking - Wrap TLS listener with logging to capture certificate selection and handshake failures - Update documentation with wildcard certificate coverage and debugging features - Normalize test data to use consistent local IP addresses This enables automatic coverage of all current and future Bose API subdomains while providing comprehensive TLS debugging for DNS redirection troubleshooting.
129 lines
3.2 KiB
Go
129 lines
3.2 KiB
Go
package certmanager
|
|
|
|
import (
|
|
"crypto/x509"
|
|
"encoding/pem"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
)
|
|
|
|
func TestCertificateManager(t *testing.T) {
|
|
tempDir, err := os.MkdirTemp("", "crypto-test")
|
|
if err != nil {
|
|
t.Fatalf("Failed to create temp dir: %v", err)
|
|
}
|
|
defer os.RemoveAll(tempDir)
|
|
|
|
cm := NewCertificateManager(filepath.Join(tempDir, "certs"))
|
|
|
|
// Test CA generation
|
|
if err := cm.EnsureCA(); err != nil {
|
|
t.Fatalf("Failed to ensure CA: %v", err)
|
|
}
|
|
|
|
if _, err := os.Stat(cm.GetCACertPath()); os.IsNotExist(err) {
|
|
t.Errorf("CA certificate not created")
|
|
}
|
|
if _, err := os.Stat(cm.GetCAKeyPath()); os.IsNotExist(err) {
|
|
t.Errorf("CA key not created")
|
|
}
|
|
|
|
// Test loading CA
|
|
caCertPEM, err := os.ReadFile(cm.GetCACertPath())
|
|
if err != nil {
|
|
t.Fatalf("Failed to read CA cert: %v", err)
|
|
}
|
|
block, _ := pem.Decode(caCertPEM)
|
|
if block == nil || block.Type != "CERTIFICATE" {
|
|
t.Errorf("Invalid CA certificate PEM")
|
|
}
|
|
caCert, err := x509.ParseCertificate(block.Bytes)
|
|
if err != nil {
|
|
t.Fatalf("Failed to parse CA cert: %v", err)
|
|
}
|
|
if !caCert.IsCA {
|
|
t.Errorf("Generated certificate is not a CA")
|
|
}
|
|
|
|
// Test certificate generation
|
|
domains := []string{"streaming.bose.com", "updates.bose.com"}
|
|
certPEM, keyPEM, err := cm.GenerateCertificate(domains)
|
|
if err != nil {
|
|
t.Fatalf("Failed to generate certificate: %v", err)
|
|
}
|
|
|
|
if len(certPEM) == 0 || len(keyPEM) == 0 {
|
|
t.Errorf("Generated certificate or key is empty")
|
|
}
|
|
|
|
// Verify generated certificate
|
|
block, _ = pem.Decode(certPEM)
|
|
if block == nil || block.Type != "CERTIFICATE" {
|
|
t.Errorf("Invalid certificate PEM")
|
|
}
|
|
cert, err := x509.ParseCertificate(block.Bytes)
|
|
if err != nil {
|
|
t.Fatalf("Failed to parse certificate: %v", err)
|
|
}
|
|
|
|
if cert.Subject.CommonName != domains[0] {
|
|
t.Errorf("Expected CommonName %s, got %s", domains[0], cert.Subject.CommonName)
|
|
}
|
|
|
|
// Check DNS names
|
|
if len(cert.DNSNames) != len(domains) {
|
|
t.Errorf("Expected %d DNS names, got %d", len(domains), len(cert.DNSNames))
|
|
}
|
|
|
|
// Verify against CA
|
|
roots := x509.NewCertPool()
|
|
roots.AddCert(caCert)
|
|
opts := x509.VerifyOptions{
|
|
DNSName: domains[0],
|
|
Roots: roots,
|
|
}
|
|
|
|
if _, err := cert.Verify(opts); err != nil {
|
|
t.Errorf("Failed to verify certificate against CA: %v", err)
|
|
}
|
|
|
|
// Test GetServerTLSConfig
|
|
tlsConfig, err := cm.GetServerTLSConfig(domains)
|
|
if err != nil {
|
|
t.Fatalf("Failed to get TLS config: %v", err)
|
|
}
|
|
|
|
if tlsConfig == nil {
|
|
t.Fatal("TLS config is nil")
|
|
}
|
|
|
|
if len(tlsConfig.Certificates) == 0 {
|
|
t.Fatal("TLS config has no certificates")
|
|
}
|
|
|
|
// Test certificate regeneration if domains change
|
|
newDomains := append(domains, "foo.local")
|
|
tlsConfig2, err := cm.GetServerTLSConfig(newDomains)
|
|
if err != nil {
|
|
t.Fatalf("Failed to get updated TLS config: %v", err)
|
|
}
|
|
if len(tlsConfig2.Certificates[0].Leaf.DNSNames) < 3 {
|
|
// Note: tls.LoadX509KeyPair doesn't populate Leaf by default.
|
|
// We should parse it manually or rely on the file existence/content.
|
|
certBytes, _ := os.ReadFile(cm.GetServerCertPEMPath())
|
|
block, _ := pem.Decode(certBytes)
|
|
cert, _ := x509.ParseCertificate(block.Bytes)
|
|
found := false
|
|
for _, d := range cert.DNSNames {
|
|
if d == "foo.local" {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
if !found {
|
|
t.Errorf("Regenerated certificate does not contain new domain")
|
|
}
|
|
}
|
|
}
|