Separate the window sentence from the wrapped error so a bad certificate file is not reported as a key mismatch.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-07 15:01:38 +02:00
co-authored by Cursor
parent a405048f23
commit e642b24be0
17 changed files with 842 additions and 742 deletions
+51 -36
View File
@@ -11,6 +11,7 @@ import (
"encoding/asn1"
"encoding/pem"
"errors"
"fmt"
"io/fs"
"os"
"path/filepath"
@@ -84,13 +85,24 @@ func writeClientCert(dir, certPEM string) error {
return writeMode(filepath.Join(dir, certFileName), []byte(certPEM), 0o644)
}
func csrNewerThanCert(dir string) bool {
csr, err1 := os.Stat(filepath.Join(dir, csrFileName))
cert, err2 := os.Stat(filepath.Join(dir, certFileName))
if err1 != nil || err2 != nil {
return false
func csrNewerThanCert(dir string) (bool, error) {
csrPath := filepath.Join(dir, csrFileName)
certPath := filepath.Join(dir, certFileName)
csr, err := os.Stat(csrPath)
if err != nil && !errors.Is(err, fs.ErrNotExist) {
return false, fmt.Errorf("stat %s: %w", csrPath, err)
}
return csr.ModTime().After(cert.ModTime())
if err != nil {
return false, nil
}
cert, err := os.Stat(certPath)
if err != nil && !errors.Is(err, fs.ErrNotExist) {
return false, fmt.Errorf("stat %s: %w", certPath, err)
}
if err != nil {
return false, nil
}
return csr.ModTime().After(cert.ModTime()), nil
}
func readCSR(dir string) (string, error) {
@@ -103,7 +115,7 @@ func readCSR(dir string) (string, error) {
// prepareIdentity checks a saved certificate or creates the key and signing
// request. fatal is a window message when the station must stop.
func prepareIdentity(dir, callsign string) (tls.Certificate, bool, string) {
func prepareIdentity(dir, callsign string) (tls.Certificate, bool, string, error) {
certPath := filepath.Join(dir, certFileName)
keyPath := filepath.Join(dir, keyFileName)
_, certErr := os.Stat(certPath)
@@ -111,100 +123,103 @@ func prepareIdentity(dir, callsign string) (tls.Certificate, bool, string) {
certExists := certErr == nil
keyExists := keyErr == nil
if certErr != nil && !errors.Is(certErr, fs.ErrNotExist) {
return tls.Certificate{}, false, "Cannot create " + certPath
return tls.Certificate{}, false, "Cannot create " + certPath, fmt.Errorf("stat certificate: %w", certErr)
}
if keyErr != nil && !errors.Is(keyErr, fs.ErrNotExist) {
return tls.Certificate{}, false, "Cannot create " + keyPath
return tls.Certificate{}, false, "Cannot create " + keyPath, fmt.Errorf("stat key: %w", keyErr)
}
if certExists && !keyExists {
return tls.Certificate{}, false, "Certificate key is missing"
return tls.Certificate{}, false, "Certificate key is missing", nil
}
if certExists && keyExists {
pair, msg := loadPair(certPath, keyPath, callsign)
pair, msg, err := loadPair(certPath, keyPath, callsign)
if msg != "" {
return tls.Certificate{}, false, msg
return tls.Certificate{}, false, msg, err
}
if msg := ensureCSR(dir, callsign); msg != "" {
return tls.Certificate{}, false, msg
if msg, err := ensureCSR(dir, callsign); msg != "" {
return tls.Certificate{}, false, msg, err
}
return pair, true, ""
return pair, true, "", nil
}
if msg := ensureKeyAndCSR(dir, callsign, !keyExists); msg != "" {
return tls.Certificate{}, false, msg
if msg, err := ensureKeyAndCSR(dir, callsign, !keyExists); msg != "" {
return tls.Certificate{}, false, msg, err
}
return tls.Certificate{}, false, ""
return tls.Certificate{}, false, "", nil
}
func loadPair(certPath, keyPath, callsign string) (tls.Certificate, string) {
func loadPair(certPath, keyPath, callsign string) (tls.Certificate, string, error) {
cert, err := loadCert(certPath)
if err != nil {
return tls.Certificate{}, "Certificate does not match the key"
return tls.Certificate{}, "Cannot create " + certPath, fmt.Errorf("read certificate: %w", err)
}
key, err := loadKey(keyPath)
if err != nil {
return tls.Certificate{}, "Certificate does not match the key"
return tls.Certificate{}, "Cannot create " + keyPath, fmt.Errorf("read key: %w", err)
}
pub, ok := cert.PublicKey.(*rsa.PublicKey)
if !ok || !pub.Equal(&key.PublicKey) {
return tls.Certificate{}, "Certificate does not match the key"
return tls.Certificate{}, "Certificate does not match the key", nil
}
if cert.Subject.CommonName != callsign {
return tls.Certificate{}, "Certificate callsign does not match"
return tls.Certificate{}, "Certificate callsign does not match", nil
}
return tls.Certificate{
Certificate: [][]byte{cert.Raw},
PrivateKey: key,
Leaf: cert,
}, ""
}, "", nil
}
func ensureCSR(dir, callsign string) string {
func ensureCSR(dir, callsign string) (string, error) {
csrPath := filepath.Join(dir, csrFileName)
_, err := os.Stat(csrPath)
if err == nil {
return ""
return "", nil
}
if !errors.Is(err, fs.ErrNotExist) {
return "Cannot create " + csrPath
return "Cannot create " + csrPath, fmt.Errorf("stat signing request: %w", err)
}
key, err := loadKey(filepath.Join(dir, keyFileName))
if err != nil {
return "Cannot create " + csrPath
return "Cannot create " + csrPath, fmt.Errorf("read key: %w", err)
}
if err := writeCSR(csrPath, key, callsign); err != nil {
return "Cannot create " + csrPath
return "Cannot create " + csrPath, err
}
return ""
return "", nil
}
func ensureKeyAndCSR(dir, callsign string, created bool) string {
func ensureKeyAndCSR(dir, callsign string, created bool) (string, error) {
keyPath := filepath.Join(dir, keyFileName)
var key *rsa.PrivateKey
var err error
if created {
key, err = rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
return "Cannot create " + keyPath
return "Cannot create " + keyPath, fmt.Errorf("generate key: %w", err)
}
der := x509.MarshalPKCS1PrivateKey(key)
body := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: der})
if err := writeNew(keyPath, body, 0o600); err != nil {
return "Cannot create " + keyPath
return "Cannot create " + keyPath, err
}
} else {
key, err = loadKey(keyPath)
if err != nil {
return "Cannot create " + keyPath
return "Cannot create " + keyPath, fmt.Errorf("read key: %w", err)
}
}
csrPath := filepath.Join(dir, csrFileName)
_, csrErr := os.Stat(csrPath)
if csrErr != nil && !errors.Is(csrErr, fs.ErrNotExist) {
return "Cannot create " + csrPath, fmt.Errorf("stat signing request: %w", csrErr)
}
if created || errors.Is(csrErr, fs.ErrNotExist) {
if err := writeCSR(csrPath, key, callsign); err != nil {
return "Cannot create " + csrPath
return "Cannot create " + csrPath, err
}
}
return ""
return "", nil
}
func writeCSR(path string, key *rsa.PrivateKey, callsign string) error {