Files
Charon/backend/internal/services/certificate_validator_extra_coverage_test.go

257 lines
7.7 KiB
Go

package services
import (
"crypto/ecdsa"
"crypto/ed25519"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"math/big"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// --- ValidateKeyMatch ECDSA ---
func TestValidateKeyMatch_ECDSA_Success(t *testing.T) {
cert, _, _, _ := makeECDSACertAndKey(t, "ecdsa-match.test")
priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
require.NoError(t, err)
// Use the actual key that signed the cert
ecCert, ecKey, _, _ := makeECDSACertAndKey(t, "ecdsa-ok.test")
err = ValidateKeyMatch(ecCert, ecKey)
assert.NoError(t, err)
// Mismatch: different ECDSA key
err = ValidateKeyMatch(cert, priv)
assert.Error(t, err)
assert.Contains(t, err.Error(), "ECDSA key mismatch")
}
func TestValidateKeyMatch_ECDSA_WrongKeyType(t *testing.T) {
cert, _, _, _ := makeECDSACertAndKey(t, "ecdsa-wrong.test")
rsaKey, err := rsa.GenerateKey(rand.Reader, 2048)
require.NoError(t, err)
err = ValidateKeyMatch(cert, rsaKey)
assert.Error(t, err)
assert.Contains(t, err.Error(), "key type mismatch")
}
// --- ValidateKeyMatch Ed25519 ---
func TestValidateKeyMatch_Ed25519_Success(t *testing.T) {
cert, priv, _, _ := makeEd25519CertAndKey(t, "ed25519-ok.test")
err := ValidateKeyMatch(cert, priv)
assert.NoError(t, err)
}
func TestValidateKeyMatch_Ed25519_Mismatch(t *testing.T) {
cert, _, _, _ := makeEd25519CertAndKey(t, "ed25519-mismatch.test")
_, otherPriv, err := ed25519.GenerateKey(rand.Reader)
require.NoError(t, err)
err = ValidateKeyMatch(cert, otherPriv)
assert.Error(t, err)
assert.Contains(t, err.Error(), "Ed25519 key mismatch")
}
func TestValidateKeyMatch_Ed25519_WrongKeyType(t *testing.T) {
cert, _, _, _ := makeEd25519CertAndKey(t, "ed25519-wrong.test")
rsaKey, err := rsa.GenerateKey(rand.Reader, 2048)
require.NoError(t, err)
err = ValidateKeyMatch(cert, rsaKey)
assert.Error(t, err)
assert.Contains(t, err.Error(), "key type mismatch")
}
func TestValidateKeyMatch_UnsupportedKeyType(t *testing.T) {
// Create a cert with a nil public key type to trigger the default branch
cert := &x509.Certificate{PublicKey: "not-a-real-key"}
key, err := rsa.GenerateKey(rand.Reader, 2048)
require.NoError(t, err)
err = ValidateKeyMatch(cert, key)
assert.Error(t, err)
assert.Contains(t, err.Error(), "unsupported public key type")
}
// --- ConvertDERToPEM ---
func TestConvertDERToPEM_Valid(t *testing.T) {
cert, _, _, _ := makeRSACertAndKey(t, "der-to-pem.test", time.Now().Add(time.Hour))
pemStr, err := ConvertDERToPEM(cert.Raw)
require.NoError(t, err)
assert.Contains(t, pemStr, "BEGIN CERTIFICATE")
}
func TestConvertDERToPEM_Invalid(t *testing.T) {
_, err := ConvertDERToPEM([]byte("not-der-data"))
assert.Error(t, err)
assert.Contains(t, err.Error(), "invalid DER")
}
// --- ConvertPEMToDER ---
func TestConvertPEMToDER_Valid(t *testing.T) {
_, _, certPEM, _ := makeRSACertAndKey(t, "pem-to-der.test", time.Now().Add(time.Hour))
derData, err := ConvertPEMToDER(string(certPEM))
require.NoError(t, err)
assert.NotEmpty(t, derData)
// Verify it's valid DER
parsed, err := x509.ParseCertificate(derData)
require.NoError(t, err)
assert.Equal(t, "pem-to-der.test", parsed.Subject.CommonName)
}
func TestConvertPEMToDER_NoPEMBlock(t *testing.T) {
_, err := ConvertPEMToDER("not-pem-data")
assert.Error(t, err)
assert.Contains(t, err.Error(), "failed to decode PEM")
}
func TestConvertPEMToDER_InvalidCert(t *testing.T) {
fakePEM := string(pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: []byte("garbage")}))
_, err := ConvertPEMToDER(fakePEM)
assert.Error(t, err)
assert.Contains(t, err.Error(), "invalid certificate PEM")
}
// --- ConvertPEMToPFX ---
func TestConvertPEMToPFX_Valid(t *testing.T) {
_, _, certPEM, keyPEM := makeRSACertAndKey(t, "pem-to-pfx.test", time.Now().Add(time.Hour))
pfxData, err := ConvertPEMToPFX(string(certPEM), string(keyPEM), "", "test-password")
require.NoError(t, err)
assert.NotEmpty(t, pfxData)
}
func TestConvertPEMToPFX_WithChain(t *testing.T) {
_, _, certPEM, keyPEM := makeRSACertAndKey(t, "pfx-chain.test", time.Now().Add(time.Hour))
_, _, chainPEM, _ := makeRSACertAndKey(t, "pfx-ca.test", time.Now().Add(time.Hour))
pfxData, err := ConvertPEMToPFX(string(certPEM), string(keyPEM), string(chainPEM), "pass")
require.NoError(t, err)
assert.NotEmpty(t, pfxData)
}
func TestConvertPEMToPFX_BadCert(t *testing.T) {
_, err := ConvertPEMToPFX("not-pem", "not-pem", "", "pass")
assert.Error(t, err)
assert.Contains(t, err.Error(), "cert PEM")
}
func TestConvertPEMToPFX_BadKey(t *testing.T) {
_, _, certPEM, _ := makeRSACertAndKey(t, "pfx-badkey.test", time.Now().Add(time.Hour))
_, err := ConvertPEMToPFX(string(certPEM), "not-pem", "", "pass")
assert.Error(t, err)
assert.Contains(t, err.Error(), "key PEM")
}
// --- ExtractCertificateMetadata ---
func TestExtractCertificateMetadata_Nil(t *testing.T) {
result := ExtractCertificateMetadata(nil)
assert.Nil(t, result)
}
func TestExtractCertificateMetadata_Valid(t *testing.T) {
cert, _, _, _ := makeRSACertAndKey(t, "metadata.test", time.Now().Add(24*time.Hour))
meta := ExtractCertificateMetadata(cert)
require.NotNil(t, meta)
assert.NotEmpty(t, meta.Fingerprint)
assert.NotEmpty(t, meta.SerialNumber)
assert.Contains(t, meta.KeyType, "RSA")
assert.Contains(t, meta.Domains, "metadata.test")
}
func TestExtractCertificateMetadata_WithSANs(t *testing.T) {
priv, err := rsa.GenerateKey(rand.Reader, 2048)
require.NoError(t, err)
tmpl := &x509.Certificate{
SerialNumber: big.NewInt(42),
Subject: pkix.Name{CommonName: "san.test", Organization: []string{"Test Org"}},
Issuer: pkix.Name{Organization: []string{"Test Issuer"}},
NotBefore: time.Now(),
NotAfter: time.Now().Add(time.Hour),
DNSNames: []string{"san.test", "alt.test", "other.test"},
}
der, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, &priv.PublicKey, priv)
require.NoError(t, err)
cert, err := x509.ParseCertificate(der)
require.NoError(t, err)
meta := ExtractCertificateMetadata(cert)
require.NotNil(t, meta)
assert.Contains(t, meta.Domains, "san.test")
assert.Contains(t, meta.Domains, "alt.test")
assert.Contains(t, meta.Domains, "other.test")
assert.Equal(t, "Test Org", meta.IssuerOrg)
}
// --- detectKeyType ---
func TestDetectKeyType_Ed25519(t *testing.T) {
cert, _, _, _ := makeEd25519CertAndKey(t, "ed25519-type.test")
assert.Equal(t, "Ed25519", detectKeyType(cert))
}
func TestDetectKeyType_RSA(t *testing.T) {
cert, _, _, _ := makeRSACertAndKey(t, "rsa-type.test", time.Now().Add(time.Hour))
kt := detectKeyType(cert)
assert.Contains(t, kt, "RSA-")
}
func TestDetectKeyType_ECDSA_P256(t *testing.T) {
cert, _, _, _ := makeECDSACertAndKey(t, "p256-type.test")
assert.Equal(t, "ECDSA-P256", detectKeyType(cert))
}
// --- formatSerial ---
func TestFormatSerial_Nil(t *testing.T) {
assert.Equal(t, "", formatSerial(nil))
}
func TestFormatSerial_Value(t *testing.T) {
result := formatSerial(big.NewInt(256))
assert.NotEmpty(t, result)
assert.Contains(t, result, ":")
}
// --- formatFingerprint ---
func TestFormatFingerprint_Normal(t *testing.T) {
result := formatFingerprint("aabbccdd")
assert.Equal(t, "AA:BB:CC:DD", result)
}
func TestFormatFingerprint_OddLength(t *testing.T) {
result := formatFingerprint("aabbc")
assert.Contains(t, result, "AA:BB")
}
// --- DetectFormat DER ---
func TestDetectFormat_DER(t *testing.T) {
cert, _, _, _ := makeRSACertAndKey(t, "detect-der.test", time.Now().Add(time.Hour))
format := DetectFormat(cert.Raw)
assert.Equal(t, FormatDER, format)
}
func TestDetectFormat_PEM(t *testing.T) {
_, _, certPEM, _ := makeRSACertAndKey(t, "detect-pem.test", time.Now().Add(time.Hour))
format := DetectFormat(certPEM)
assert.Equal(t, FormatPEM, format)
}