Skip to content

Commit

Permalink
Add full support for ECDSA roots (#50)
Browse files Browse the repository at this point in the history
  • Loading branch information
aarongable committed Dec 8, 2023
1 parent 4c461f2 commit 6c6d1f4
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 16 deletions.
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
module github.com/jsha/minica

go 1.15
67 changes: 51 additions & 16 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package main
import (
"bytes"
"crypto"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"crypto/sha1"
Expand Down Expand Up @@ -36,15 +38,15 @@ type issuer struct {
cert *x509.Certificate
}

func getIssuer(keyFile, certFile string) (*issuer, error) {
func getIssuer(keyFile, certFile string, alg x509.PublicKeyAlgorithm) (*issuer, error) {
keyContents, keyErr := ioutil.ReadFile(keyFile)
certContents, certErr := ioutil.ReadFile(certFile)
if os.IsNotExist(keyErr) && os.IsNotExist(certErr) {
err := makeIssuer(keyFile, certFile)
err := makeIssuer(keyFile, certFile, alg)
if err != nil {
return nil, err
}
return getIssuer(keyFile, certFile)
return getIssuer(keyFile, certFile, alg)
} else if keyErr != nil {
return nil, fmt.Errorf("%s (but %s exists)", keyErr, certFile)
} else if certErr != nil {
Expand Down Expand Up @@ -74,10 +76,25 @@ func readPrivateKey(keyContents []byte) (crypto.Signer, error) {
block, _ := pem.Decode(keyContents)
if block == nil {
return nil, fmt.Errorf("no PEM found")
} else if block.Type != "RSA PRIVATE KEY" && block.Type != "ECDSA PRIVATE KEY" {
return nil, fmt.Errorf("incorrect PEM type %s", block.Type)
} else if block.Type == "PRIVATE KEY" {
signer, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
return nil, fmt.Errorf("failed to parse PKCS8: %w", err)
}
switch t := signer.(type) {
case *rsa.PrivateKey:
return signer.(*rsa.PrivateKey), nil
case *ecdsa.PrivateKey:
return signer.(*ecdsa.PrivateKey), nil
default:
return nil, fmt.Errorf("unsupported PKCS8 key type: %t", t)
}
} else if block.Type == "RSA PRIVATE KEY" {
return x509.ParsePKCS1PrivateKey(block.Bytes)
} else if block.Type == "EC PRIVATE KEY" || block.Type == "ECDSA PRIVATE KEY" {
return x509.ParseECPrivateKey(block.Bytes)
}
return x509.ParsePKCS1PrivateKey(block.Bytes)
return nil, fmt.Errorf("incorrect PEM type %s", block.Type)
}

func readCert(certContents []byte) (*x509.Certificate, error) {
Expand All @@ -90,8 +107,8 @@ func readCert(certContents []byte) (*x509.Certificate, error) {
return x509.ParseCertificate(block.Bytes)
}

func makeIssuer(keyFile, certFile string) error {
key, err := makeKey(keyFile)
func makeIssuer(keyFile, certFile string, alg x509.PublicKeyAlgorithm) error {
key, err := makeKey(keyFile, alg)
if err != nil {
return err
}
Expand All @@ -102,12 +119,22 @@ func makeIssuer(keyFile, certFile string) error {
return nil
}

func makeKey(filename string) (*rsa.PrivateKey, error) {
key, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
return nil, err
func makeKey(filename string, alg x509.PublicKeyAlgorithm) (crypto.Signer, error) {
var key crypto.Signer
var err error
switch {
case alg == x509.RSA:
key, err = rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
return nil, err
}
case alg == x509.ECDSA:
key, err = ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
if err != nil {
return nil, err
}
}
der := x509.MarshalPKCS1PrivateKey(key)
der, err := x509.MarshalPKCS8PrivateKey(key)
if err != nil {
return nil, err
}
Expand All @@ -117,7 +144,7 @@ func makeKey(filename string) (*rsa.PrivateKey, error) {
}
defer file.Close()
err = pem.Encode(file, &pem.Block{
Type: "RSA PRIVATE KEY",
Type: "PRIVATE KEY",
Bytes: der,
})
if err != nil {
Expand Down Expand Up @@ -227,7 +254,7 @@ func sign(iss *issuer, domains []string, ipAddresses []string) (*x509.Certificat
if err != nil && !os.IsExist(err) {
return nil, err
}
key, err := makeKey(fmt.Sprintf("%s/key.pem", cnFolder))
key, err := makeKey(fmt.Sprintf("%s/key.pem", cnFolder), x509.RSA)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -287,6 +314,7 @@ func split(s string) (results []string) {
func main2() error {
var caKey = flag.String("ca-key", "minica-key.pem", "Root private key filename, PEM encoded.")
var caCert = flag.String("ca-cert", "minica.pem", "Root certificate filename, PEM encoded.")
var caAlg = flag.String("ca-alg", "rsa", "Root keypair algorithm: RSA or ECDSA. Only used if generating new.")
var domains = flag.String("domains", "", "Comma separated domain names to include as Server Alternative Names.")
var ipAddresses = flag.String("ip-addresses", "", "Comma separated IP addresses to include as Server Alternative Names.")
flag.Usage = func() {
Expand Down Expand Up @@ -317,6 +345,13 @@ will not overwrite existing keys or certificates.
flag.Usage()
os.Exit(1)
}
alg := x509.RSA
if strings.ToLower(*caAlg) == "ecdsa" {
alg = x509.ECDSA
} else if strings.ToLower(*caCert) != "rsa" {
fmt.Printf("Unrecognized algorithm: %s (use RSA or ECDSA)\n", *caAlg)
os.Exit(1)
}
if len(flag.Args()) > 0 {
fmt.Printf("Extra arguments: %s (maybe there are spaces in your domain list?)\n", flag.Args())
os.Exit(1)
Expand All @@ -336,7 +371,7 @@ will not overwrite existing keys or certificates.
os.Exit(1)
}
}
issuer, err := getIssuer(*caKey, *caCert)
issuer, err := getIssuer(*caKey, *caCert, alg)
if err != nil {
return err
}
Expand Down

0 comments on commit 6c6d1f4

Please sign in to comment.