aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Clerc <jclerc@google.com>2015-09-11 20:38:31 +0200
committerJeremy Clerc <jeremy@clerc.io>2015-09-11 20:38:31 +0200
commitbf2bb200a62a965b28ded738e1eb5a18c28b1d63 (patch)
tree78898581307252505e936ce631c9805838967616
parente08d02983d7ae67f33b66145ea128d5fefaac065 (diff)
downloadeasypki-bf2bb200a62a965b28ded738e1eb5a18c28b1d63.tar.xz
move initpki, add revoke
moved initpki to easyca package add revoke command and method
-rw-r--r--cmd/easyca/main.go66
-rw-r--r--pkg/easyca/easyca.go155
2 files changed, 178 insertions, 43 deletions
diff --git a/cmd/easyca/main.go b/cmd/easyca/main.go
index e4a5ff7..2991a70 100644
--- a/cmd/easyca/main.go
+++ b/cmd/easyca/main.go
@@ -3,7 +3,6 @@ package main
import (
"crypto/x509"
"crypto/x509/pkix"
- "fmt"
"log"
"net"
"os"
@@ -20,43 +19,10 @@ import (
func initPki(c *cli.Context) {
log.Print("generating new pki structure")
- 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")
+ err := easyca.GeneratePKIStructure(filepath.Join(c.GlobalString("root")))
if err != nil {
- log.Fatalf("write crlnumber: %v", err)
+ log.Fatalf("generate pki structure: %v", err)
}
- if n == 0 {
- log.Fatal("write crlnumber, written 0 bytes")
- }
- log.Print("created crlnumber")
}
func createBundle(c *cli.Context) {
@@ -115,7 +81,21 @@ func createBundle(c *cli.Context) {
if err != nil {
log.Fatal(err)
}
-
+}
+func revoke(c *cli.Context) {
+ if !c.Args().Present() {
+ cli.ShowSubcommandHelp(c)
+ log.Fatalf("Usage: %v path/to/cert.crt", c.Command.FullName())
+ }
+ crtPath := c.Args().First()
+ crt, err := easyca.GetCertificate(crtPath)
+ if err != nil {
+ log.Fatalf("get certificate (%v): %v", crtPath, err)
+ }
+ err = easyca.RevokeSerial(c.GlobalString("root"), crt.SerialNumber)
+ if err != nil {
+ log.Fatalf("revoke serial %X: %v", crt.SerialNumber, err)
+ }
}
func parseArgs() {
@@ -136,9 +116,15 @@ func parseArgs() {
}
app.Commands = []cli.Command{
{
- Name: "init",
- Usage: "create directory structure",
- Action: initPki,
+ Name: "init",
+ Description: "create directory structure",
+ Action: initPki,
+ },
+ {
+ Name: "revoke",
+ Usage: "revoke path/to/cert",
+ Description: "revoke certificate",
+ Action: revoke,
},
{
Name: "create",
diff --git a/pkg/easyca/easyca.go b/pkg/easyca/easyca.go
index 2bd43fe..b7521da 100644
--- a/pkg/easyca/easyca.go
+++ b/pkg/easyca/easyca.go
@@ -1,6 +1,7 @@
package easyca
import (
+ "bufio"
"crypto/rand"
"crypto/rsa"
"crypto/sha1"
@@ -12,9 +13,22 @@ import (
"math/big"
"os"
"path/filepath"
+ "regexp"
"time"
)
+var (
+ // Index format
+ // 0 full string
+ // 1 Valid/Revoked/Expired
+ // 2 Expiration date
+ // 3 Revocation date
+ // 4 Serial
+ // 5 Filename
+ // 6 Subject
+ indexRegexp = regexp.MustCompile("^(V|R|E)\t([0-9]{12}Z)\t([0-9]{12}Z)?\t([0-9a-fA-F]{2,})\t([^\t]+)\t(.+)")
+)
+
func GeneratePrivateKey(path string) (*rsa.PrivateKey, error) {
keyFile, err := os.Create(path)
if err != nil {
@@ -39,8 +53,13 @@ func GeneratePrivateKey(path string) (*rsa.PrivateKey, error) {
func GenerateCertifcate(pkiroot, name string, template *x509.Certificate) error {
// TODO(jclerc): check that pki has been init
+ var crtPath string
privateKeyPath := filepath.Join(pkiroot, "private", name+".key")
- crtPath := filepath.Join(pkiroot, name+".crt")
+ if name == "ca" {
+ crtPath = filepath.Join(pkiroot, name+".crt")
+ } else {
+ crtPath = filepath.Join(pkiroot, "issued", name+".crt")
+ }
var caCrt *x509.Certificate
var caKey *rsa.PrivateKey
@@ -150,8 +169,72 @@ func GetCA(pkiroot string) (*x509.Certificate, *rsa.PrivateKey, error) {
return caCrt, caKey, nil
}
+func RevokeSerial(pkiroot string, serial *big.Int) error {
+ f, err := os.OpenFile(filepath.Join(pkiroot, "index.txt"), os.O_RDWR, 0644)
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+
+ var lines []string
+ scanner := bufio.NewScanner(f)
+ for scanner.Scan() {
+ matches := indexRegexp.FindStringSubmatch(scanner.Text())
+ if len(matches) != 7 {
+ return fmt.Errorf("wrong line format")
+ }
+ matchedSerial := big.NewInt(0)
+ fmt.Sscanf(matches[4], "%X", matchedSerial)
+ if matchedSerial.Cmp(serial) == 0 {
+ if matches[1] == "R" {
+ return fmt.Errorf("certificate already revoked")
+ }
+
+ lines = append(lines, fmt.Sprintf("R\t%v\t%vZ\t%v\t%v\t%v",
+ matches[2],
+ time.Now().UTC().Format("060102150405"),
+ matches[4],
+ matches[5],
+ matches[6]))
+ } else {
+ lines = append(lines, matches[0])
+ }
+ }
+
+ f.Truncate(0)
+ f.Seek(0, 0)
+
+ for _, line := range lines {
+ n, err := fmt.Fprintln(f, line)
+ if err != nil {
+ return fmt.Errorf("write line: %v", err)
+ }
+ if n == 0 {
+ return fmt.Errorf("supposed to write [%v], written 0 bytes", line)
+ }
+ }
+ return nil
+}
+
+func GetCertificate(path string) (*x509.Certificate, error) {
+ crtBytes, err := ioutil.ReadFile(path)
+ if err != nil {
+ return nil, fmt.Errorf("read crt: %v", err)
+ }
+ p, _ := pem.Decode(crtBytes)
+ if p == nil {
+ return nil, fmt.Errorf("pem decode did not found pem encoded cert")
+ }
+ crt, err := x509.ParseCertificate(p.Bytes)
+ if err != nil {
+ return nil, fmt.Errorf("parse crt: %v", err)
+ }
+
+ return crt, 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)
+ f, err := os.OpenFile(filepath.Join(pkiroot, "index.txt"), os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
return err
}
@@ -162,7 +245,7 @@ func WriteIndex(pkiroot, filename string, crt *x509.Certificate) error {
if len(serialOutput)%2 == 1 {
serialOutput = "0" + serialOutput
}
-
+ // subject: /C=FR/ST=IDF/O=Umbrella Corporation/CN=test.clerc.io
// 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",
@@ -178,3 +261,69 @@ func WriteIndex(pkiroot, filename string, crt *x509.Certificate) error {
}
return nil
}
+
+// |-ca.crt
+// |-crlnumber
+// |-index.txt
+// |-index.txt.attr
+// |-serial
+// |-issued/
+// |- name.crt
+// |-private
+// |- ca.key
+// |- name.key
+func GeneratePKIStructure(pkiroot string) error {
+
+ for _, dir := range []string{"private", "issued"} {
+ err := os.Mkdir(filepath.Join(pkiroot, dir), 0755)
+ if err != nil {
+ return fmt.Errorf("creating dir %v: %v", dir, err)
+ }
+ }
+
+ serial, err := os.Create(filepath.Join(pkiroot, "serial"))
+ if err != nil {
+ return fmt.Errorf("create serial: %v", err)
+ }
+ defer serial.Close()
+ n, err := fmt.Fprintln(serial, "01")
+ if err != nil {
+ return fmt.Errorf("write serial: %v", err)
+ }
+ if n == 0 {
+ return fmt.Errorf("write serial, written 0 bytes")
+ }
+
+ crlnumber, err := os.Create(filepath.Join(pkiroot, "crlnumber"))
+ if err != nil {
+ return fmt.Errorf("create crlnumber: %v", err)
+ }
+ defer crlnumber.Close()
+ n, err = fmt.Fprintln(crlnumber, "01")
+ if err != nil {
+ return fmt.Errorf("write crlnumber: %v", err)
+ }
+ if n == 0 {
+ return fmt.Errorf("write crlnumber, written 0 bytes")
+ }
+
+ index, err := os.Create(filepath.Join(pkiroot, "index.txt"))
+ if err != nil {
+ return fmt.Errorf("create index: %v", err)
+ }
+ defer index.Close()
+
+ indexattr, err := os.Create(filepath.Join(pkiroot, "index.txt.attr"))
+ if err != nil {
+ return fmt.Errorf("create index.txt.attr: %v", err)
+ }
+ defer indexattr.Close()
+ n, err = fmt.Fprintln(indexattr, "unique_subject = no")
+ if err != nil {
+ return fmt.Errorf("write index.txt.attr: %v", err)
+ }
+ if n == 0 {
+ return fmt.Errorf("write index.txt.attr, written 0 bytes")
+ }
+ return nil
+}