gecko/staking/gen_staker_key.go

86 lines
2.8 KiB
Go

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
}