aboutsummaryrefslogtreecommitdiff
path: root/pkg/easyca/easyca.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/easyca/easyca.go')
-rw-r--r--pkg/easyca/easyca.go155
1 files changed, 152 insertions, 3 deletions
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
+}