Checkpoint

This commit is contained in:
2025-10-06 22:25:23 +02:00
parent a23259cfdc
commit a254b306f2
48 changed files with 3327 additions and 212 deletions

119
ca/authority.go Normal file
View File

@@ -0,0 +1,119 @@
package ca
import (
"crypto"
"crypto/rand"
"crypto/tls"
"crypto/x509"
"crypto/x509/pkix"
"fmt"
"math/big"
"net"
"strings"
"sync"
"time"
"git.maze.io/maze/styx/internal/cryptutil"
"git.maze.io/maze/styx/logger"
"github.com/miekg/dns"
)
type CertificateAuthority interface {
GetCertificate(commonName string, dnsNames []string, ips []net.IP) (*tls.Certificate, error)
}
type ca struct {
cert *x509.Certificate
key crypto.PrivateKey
cache sync.Map
}
func Open(certData, keyData string) (CertificateAuthority, error) {
cert, key, err := cryptutil.LoadKeyPair(certData, keyData)
if err != nil {
return nil, err
} else if !cert.IsCA {
return nil, fmt.Errorf("ca: certificate for %s is not a certificate authority", cert.Subject.String())
}
return &ca{
cert: cert,
key: key,
}, nil
}
func (ca *ca) GetCertificate(cn string, names []string, ips []net.IP) (*tls.Certificate, error) {
var (
log = logger.StandardLog.Values(logger.Values{
"cn": cn,
"names": names,
"ips": ips,
})
now = time.Now().UTC()
parent = parentDomain(cn)
)
if cn == parent {
names = append(names, "*."+cn)
} else {
names = append(names, "*."+parent, cn)
cn = parent
log = log.Value("cn", cn)
}
if v, ok := ca.cache.Load(parent); ok {
if cert, ok := v.(*tls.Certificate); ok && now.After(cert.Leaf.NotBefore) && now.Before(cert.Leaf.NotAfter.Add(-time.Hour)) {
log.Value("valid", cert.Leaf.NotAfter.Sub(now)).Debug("Using cached certificate")
return cert, nil
}
log.Debug("Cached certificate invalid")
ca.cache.Delete(parent)
}
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
if err != nil {
return nil, fmt.Errorf("ca: failed to generate serial number: %w", err)
}
notBefore := now.Round(24 * time.Hour)
notAfter := notBefore.Add(48 * time.Hour)
log.Values(logger.Values{
"serial": serialNumber.String(),
"subject": pkix.Name{CommonName: cn}.String(),
}).Debug("Generating certificate")
template := &x509.Certificate{
SerialNumber: serialNumber,
KeyUsage: x509.KeyUsageDataEncipherment | x509.KeyUsageDigitalSignature,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
Subject: pkix.Name{CommonName: cn},
DNSNames: names,
IPAddresses: ips,
PublicKey: cryptutil.PublicKey(ca.key),
NotBefore: notBefore,
NotAfter: notAfter,
}
der, err := x509.CreateCertificate(rand.Reader, template, ca.cert, template.PublicKey, ca.key)
if err != nil {
return nil, err
}
cert, err := x509.ParseCertificate(der)
if err != nil {
return nil, err
}
output := &tls.Certificate{
Certificate: [][]byte{der},
Leaf: cert,
PrivateKey: ca.key,
}
ca.cache.Store(parent, output)
return output, nil
}
func parentDomain(name string) string {
part := dns.SplitDomainName(name)
if len(part) <= 2 {
return name
}
return strings.Join(part[1:], ".")
}