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:
+51
-36
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user