Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions crypto.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
"fmt"
"hash/fnv"
"io/fs"
"os"
"sort"
"strings"

Expand Down Expand Up @@ -370,3 +371,45 @@ const (
RSA4096 = KeyType("rsa4096")
RSA8192 = KeyType("rsa8192")
)

// FileKeyGenerator reads a pre-existing private key from a file
// instead of generating a new random one.
type FileKeyGenerator struct {
// KeyFilename is the path to the PEM-encoded private key file.
KeyFilename string
}

// GenerateKey reads the private key from the file, parses the PEM block,
// and returns the underlying crypto.PrivateKey expected by CertMagic.
func (fkg FileKeyGenerator) GenerateKey() (crypto.PrivateKey, error) {
if fkg.KeyFilename == "" {
return nil, errors.New("no key filename specified")
}

keyData, err := os.ReadFile(fkg.KeyFilename)
if err != nil {
return nil, fmt.Errorf("reading private key file %s: %v", fkg.KeyFilename, err)
}

block, _ := pem.Decode(keyData)
if block == nil {
return nil, fmt.Errorf("failed to find a valid PEM block in the key file: %s", fkg.KeyFilename)
}

if key, err := x509.ParsePKCS1PrivateKey(block.Bytes); err == nil {
return key, nil
}
if key, err := x509.ParsePKCS8PrivateKey(block.Bytes); err == nil {
switch key := key.(type) {
case *rsa.PrivateKey, *ecdsa.PrivateKey, ed25519.PrivateKey:
return key, nil
default:
return nil, fmt.Errorf("found unknown private key type in PKCS#8 wrapping: %T", key)
}
}
if key, err := x509.ParseECPrivateKey(block.Bytes); err == nil {
return key, nil
}

return nil, errors.New("failed to parse private key: unsupported or invalid format")
}