aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/easyca/main.go76
-rw-r--r--pkg/easyca/easyca.go40
-rw-r--r--pkg/easyca/serial.go47
3 files changed, 121 insertions, 42 deletions
diff --git a/cmd/easyca/main.go b/cmd/easyca/main.go
index 4a16172..e4a5ff7 100644
--- a/cmd/easyca/main.go
+++ b/cmd/easyca/main.go
@@ -3,6 +3,7 @@ package main
import (
"crypto/x509"
"crypto/x509/pkix"
+ "fmt"
"log"
"net"
"os"
@@ -19,10 +20,43 @@ import (
func initPki(c *cli.Context) {
log.Print("generating new pki structure")
- err := os.MkdirAll(filepath.Join(c.GlobalString("root"), "private"), 0755)
+ pkiroot := filepath.Join(c.GlobalString("root"))
+
+ for _, dir := range []string{"private", "issued"} {
+ err := os.Mkdir(filepath.Join(pkiroot, dir), 0755)
+ if err != nil {
+ log.Fatalf("creating dir %v: %v", dir, err)
+ }
+ log.Printf("created %v directory", dir)
+ }
+
+ serial, err := os.Create(filepath.Join(pkiroot, "serial"))
+ if err != nil {
+ log.Fatalf("create serial: %v", err)
+ }
+ defer serial.Close()
+ n, err := fmt.Fprintln(serial, "01")
+ if err != nil {
+ log.Fatalf("write serial: %v", err)
+ }
+ if n == 0 {
+ log.Fatal("write serial, written 0 bytes")
+ }
+ log.Print("created serial")
+
+ crlnumber, err := os.Create(filepath.Join(pkiroot, "crlnumber"))
+ if err != nil {
+ log.Fatalf("create crlnumber: %v", err)
+ }
+ defer crlnumber.Close()
+ n, err = fmt.Fprintln(crlnumber, "01")
if err != nil {
- log.Fatalf("creating pki structure %v", err)
+ log.Fatalf("write crlnumber: %v", err)
}
+ if n == 0 {
+ log.Fatal("write crlnumber, written 0 bytes")
+ }
+ log.Print("created crlnumber")
}
func createBundle(c *cli.Context) {
@@ -32,24 +66,29 @@ func createBundle(c *cli.Context) {
"different name if you need multiple certs for same cn)", c.Command.FullName())
}
- var filename string
commonName := strings.Join(c.Args()[:], " ")
-
- if len(c.String("filename")) > 0 {
- filename = c.String("filename")
- } else {
+ var filename string
+ if filename = c.String("filename"); len(filename) == 0 {
filename = strings.Replace(commonName, " ", "_", -1)
filename = strings.Replace(filename, "*", "wildcard", -1)
}
+ subject := pkix.Name{CommonName: commonName}
+ if str := c.String("organization"); len(str) > 0 {
+ subject.Organization = []string{str}
+ }
+ if str := c.String("locality"); len(str) > 0 {
+ subject.Locality = []string{str}
+ }
+ if str := c.String("country"); len(str) > 0 {
+ subject.Country = []string{str}
+ }
+ if str := c.String("province"); len(str) > 0 {
+ subject.Province = []string{str}
+ }
+
template := &x509.Certificate{
- Subject: pkix.Name{
- CommonName: commonName,
- Organization: c.StringSlice("organization"),
- Locality: c.StringSlice("locality"),
- Country: c.StringSlice("country"),
- Province: c.StringSlice("province"),
- },
+ Subject: subject,
NotAfter: time.Now().AddDate(0, 0, c.Int("expire")),
}
@@ -76,6 +115,7 @@ func createBundle(c *cli.Context) {
if err != nil {
log.Fatal(err)
}
+
}
func parseArgs() {
@@ -123,20 +163,20 @@ func parseArgs() {
Name: "filename",
Usage: "filename for bundle, use when you generate multiple certs for same cn",
},
- cli.StringSliceFlag{
+ cli.StringFlag{
Name: "organization",
EnvVar: "PKI_ORGANIZATION",
},
- cli.StringSliceFlag{
+ cli.StringFlag{
Name: "locality",
EnvVar: "PKI_LOCALITY",
},
- cli.StringSliceFlag{
+ cli.StringFlag{
Name: "country",
EnvVar: "PKI_COUNTRY",
Usage: "Country name, 2 letter code",
},
- cli.StringSliceFlag{
+ cli.StringFlag{
Name: "province",
Usage: "province/state",
EnvVar: "PKI_PROVINCE",
diff --git a/pkg/easyca/easyca.go b/pkg/easyca/easyca.go
index be77ae6..2bd43fe 100644
--- a/pkg/easyca/easyca.go
+++ b/pkg/easyca/easyca.go
@@ -83,7 +83,7 @@ func GenerateCertifcate(pkiroot, name string, template *x509.Certificate) error
if err != nil {
return fmt.Errorf("get next serial: %v", err)
}
- template.SerialNumber = big.NewInt(serialNumber)
+ template.SerialNumber = serialNumber
caCrt, caKey, err = GetCA(pkiroot)
if err != nil {
@@ -110,6 +110,13 @@ func GenerateCertifcate(pkiroot, name string, template *x509.Certificate) error
return fmt.Errorf("pem encode crt: %v", err)
}
+ // I do not think we have to write the ca.crt in the index
+ if !template.IsCA {
+ WriteIndex(pkiroot, name, template)
+ if err != nil {
+ return fmt.Errorf("write index: %v", err)
+ }
+ }
return nil
}
@@ -126,6 +133,7 @@ func GetCA(pkiroot string) (*x509.Certificate, *rsa.PrivateKey, error) {
if err != nil {
return nil, nil, fmt.Errorf("parse ca private key: %v", err)
}
+
caCrtBytes, err := ioutil.ReadFile(filepath.Join(pkiroot, "ca.crt"))
if err != nil {
return nil, nil, fmt.Errorf("read ca crt: %v", err)
@@ -138,5 +146,35 @@ func GetCA(pkiroot string) (*x509.Certificate, *rsa.PrivateKey, error) {
if err != nil {
return nil, nil, fmt.Errorf("parse ca crt: %v", err)
}
+
return caCrt, caKey, nil
}
+
+func WriteIndex(pkiroot, filename string, crt *x509.Certificate) error {
+ f, err := os.OpenFile(filepath.Join(pkiroot, "index.txt"), os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+
+ serialOutput := fmt.Sprintf("%X", crt.SerialNumber)
+ // For compatibility with openssl we need an even length
+ if len(serialOutput)%2 == 1 {
+ serialOutput = "0" + serialOutput
+ }
+
+ // Date format: yymmddHHMMSSZ
+ // E|R|V<tab>Expiry<tab>[RevocationDate]<tab>Serial<tab>filename<tab>SubjectDN
+ n, err := fmt.Fprintf(f, "V\t%vZ\t\t%v\t%v.crt\t%v\n",
+ crt.NotAfter.UTC().Format("060102150405"),
+ serialOutput,
+ filename,
+ "/CN="+crt.Subject.CommonName)
+ if err != nil {
+ return err
+ }
+ if n == 0 {
+ return fmt.Errorf("written 0 bytes in index file")
+ }
+ return nil
+}
diff --git a/pkg/easyca/serial.go b/pkg/easyca/serial.go
index aded542..7fadb84 100644
--- a/pkg/easyca/serial.go
+++ b/pkg/easyca/serial.go
@@ -2,43 +2,44 @@ package easyca
import (
"fmt"
- "io/ioutil"
+ "math/big"
"os"
"path/filepath"
- "strconv"
- "strings"
)
-func NextSerial(pkiroot string) (int64, error) {
- var serial int64
- f, err := os.OpenFile(filepath.Join(pkiroot, "serial"), os.O_RDWR|os.O_CREATE, 0644)
+func NextSerial(pkiroot string) (*big.Int, error) {
+ serial := big.NewInt(0)
+
+ f, err := os.OpenFile(filepath.Join(pkiroot, "serial"), os.O_RDWR, 0644)
if err != nil {
- return 0, err
+ return nil, err
}
defer f.Close()
- out, err := ioutil.ReadAll(f)
+
+ n, err := fmt.Fscanf(f, "%X\n", serial)
if err != nil {
- return 0, err
+ return nil, err
}
- if len(out) == 0 {
- serial = 1
- } else {
- // If serial file is edited manually, it will probably get \n or \r\n
- // We make sure to clean the unwanted characters
- serial, err = strconv.ParseInt(strings.TrimSpace(string(out)), 10, 64)
- if err != nil {
- return 0, err
- }
- serial += 1
+ if n != 1 {
+ return nil, fmt.Errorf("supposed to read 1 element, read: %v", n)
}
+ next := big.NewInt(1)
+ next.Add(serial, next)
+ output := fmt.Sprintf("%X", next)
+ // For compatibility with openssl we need an even length
+ if len(output)%2 == 1 {
+ output = "0" + output
+ }
+ f.Truncate(0)
f.Seek(0, 0)
- written, err := fmt.Fprint(f, serial)
+
+ n, err = fmt.Fprintln(f, output)
if err != nil {
- return 0, err
+ return nil, err
}
- if written == 0 {
- return 0, fmt.Errorf("wanted to write %s to serial file, no byte written", written)
+ if n == 0 {
+ return nil, fmt.Errorf("supposed to write 1 element, written: %v", n)
}
return serial, nil