92 lines
1.9 KiB
Go
92 lines
1.9 KiB
Go
//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, ":")
|
||
|
|
}
|