//go:build linux || freebsd // +build linux freebsd package crypto import ( "crypto/sha256" "crypto/x509" "encoding/pem" "fmt" "os" "strings" ) // CertLoader loads and parses certificates type CertLoader struct { pool *x509.CertPool } // NewCertLoader creates new cert loader func NewCertLoader() *CertLoader { return &CertLoader{ pool: x509.NewCertPool(), } } // LoadCAFile loads CA certificates from a file func (cl *CertLoader) LoadCAFile(path string) error { data, err := os.ReadFile(path) if err != nil { return fmt.Errorf("failed to read ca file: %w", err) } if !cl.pool.AppendCertsFromPEM(data) { return fmt.Errorf("failed to parse ca certificates") } return nil } // LoadSystemCerts loads system certificates func (cl *CertLoader) LoadSystemCerts() error { pool, err := x509.SystemCertPool() if err != nil { // Fallback for systems without system certificates cl.pool = x509.NewCertPool() return nil } cl.pool = pool return nil } // GetPool returns the certificate pool func (cl *CertLoader) GetPool() *x509.CertPool { return cl.pool } // ParseCertificate parses a PEM certificate func ParseCertificate(data []byte) (*x509.Certificate, error) { block, _ := pem.Decode(data) if block == nil { return nil, fmt.Errorf("failed to decode PEM block") } return x509.ParseCertificate(block.Bytes) } // LoadCertificateFile loads a certificate from a file func LoadCertificateFile(path string) (*x509.Certificate, error) { data, err := os.ReadFile(path) if err != nil { return nil, err } return ParseCertificate(data) } // FingerprintSHA256 calculates the SHA-256 fingerprint of a certificate func FingerprintSHA256(cert *x509.Certificate) string { if cert == nil { return "" } hash := sha256.Sum256(cert.Raw) // Format as colon-separated hex pairs (like OpenSSL format) parts := make([]string, len(hash)) for i, b := range hash { parts[i] = fmt.Sprintf("%02X", b) } return strings.Join(parts, ":") }