package staking import ( "crypto/rand" "crypto/rsa" "crypto/x509" "encoding/pem" "fmt" "math/big" "os" "path/filepath" "time" ) // GenerateStakingKeyCert generates a self-signed TLS key/cert pair to use in staking // The key and files will be placed at [keyPath] and [certPath], respectively // If there is already a file at [keyPath], returns nil func GenerateStakingKeyCert(keyPath, certPath string) error { // If there is already a file at [keyPath], do nothing if _, err := os.Stat(keyPath); !os.IsNotExist(err) { return nil } // Create key to sign cert with key, err := rsa.GenerateKey(rand.Reader, 4096) if err != nil { return fmt.Errorf("couldn't generate rsa key: %w", err) } // Create self-signed staking cert certTemplate := &x509.Certificate{ SerialNumber: big.NewInt(0), NotBefore: time.Date(2000, time.January, 0, 0, 0, 0, 0, time.UTC), NotAfter: time.Now().AddDate(100, 0, 0), KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageDataEncipherment, BasicConstraintsValid: true, } certBytes, err := x509.CreateCertificate(rand.Reader, certTemplate, certTemplate, &key.PublicKey, key) if err != nil { return fmt.Errorf("couldn't create certificate: %w", err) } // Ensure directory where key/cert will live exist if err := os.MkdirAll(filepath.Dir(certPath), 0700); err != nil { return fmt.Errorf("couldn't create path for cert: %w", err) } else if err := os.MkdirAll(filepath.Dir(keyPath), 0700); err != nil { return fmt.Errorf("couldn't create path for key: %w", err) } // Write cert to disk certFile, err := os.Create(certPath) if err != nil { return fmt.Errorf("couldn't create cert file: %w", err) } if err := pem.Encode(certFile, &pem.Block{Type: "CERTIFICATE", Bytes: certBytes}); err != nil { return fmt.Errorf("couldn't write cert file: %w", err) } if err := certFile.Close(); err != nil { return fmt.Errorf("couldn't close cert file: %w", err) } if err := os.Chmod(certPath, 0400); err != nil { // Make cert read-only return fmt.Errorf("couldn't change permissions on cert: %w", err) } // Write key to disk keyOut, err := os.Create(keyPath) if err != nil { return fmt.Errorf("couldn't create key file: %w", err) } privBytes, err := x509.MarshalPKCS8PrivateKey(key) if err != nil { return fmt.Errorf("couldn't marshal private key: %w", err) } if err := pem.Encode(keyOut, &pem.Block{Type: "PRIVATE KEY", Bytes: privBytes}); err != nil { return fmt.Errorf("couldn't write private key: %w", err) } if err := keyOut.Close(); err != nil { return fmt.Errorf("couldn't close key file: %w", err) } if err := os.Chmod(keyPath, 0400); err != nil { // Make key read-only return fmt.Errorf("couldn't change permissions on key") } return nil }