From 496d9d98f45375ba15c318ce0f27f46c981af73d Mon Sep 17 00:00:00 2001 From: Richard Barnes Date: Wed, 11 Mar 2015 23:09:31 -0700 Subject: [PATCH] Add mkroot and mkcrl --- cmd/mkcrl/main.go | 113 ++++++++++++++++++++++++++++++++++ cmd/mkroot/main.go | 148 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 261 insertions(+) create mode 100644 cmd/mkcrl/main.go create mode 100644 cmd/mkroot/main.go diff --git a/cmd/mkcrl/main.go b/cmd/mkcrl/main.go new file mode 100644 index 000000000..eda067783 --- /dev/null +++ b/cmd/mkcrl/main.go @@ -0,0 +1,113 @@ +package main + +import ( + "crypto/rand" + "crypto/x509" + "crypto/x509/pkix" + "encoding/json" + "encoding/pem" + "flag" + "fmt" + "io/ioutil" + "time" + + "github.com/cloudflare/cfssl/crypto/pkcs11key" + "github.com/cloudflare/cfssl/log" +) + +var certFile = flag.String("ca", "", "JSON file for subject and validity") +var listFile = flag.String("revoked", "", "JSON list of revoked cert serials") +var module = flag.String("pkcs11-module", "", "PKCS#11 module") +var pin = flag.String("pkcs11-pin", "", "PKCS#11 password") +var token = flag.String("pkcs11-token", "", "PKCS#11 token name") +var label = flag.String("pkcs11-label", "", "PKCS#11 key label") + +type Config struct { + ThisUpdate time.Time + NextUpdate time.Time + RevokedCerts []pkix.RevokedCertificate +} + +func main() { + // Validate input + // All flags are required + flag.Parse() + missing := false + switch { + case len(*certFile) == 0: + missing = true + log.Critical("Missing cert file parameter") + fallthrough + case len(*listFile) == 0: + missing = true + log.Critical("Missing revoked list parameter") + fallthrough + case len(*module) == 0: + missing = true + log.Critical("Missing module parameter") + fallthrough + case len(*pin) == 0: + missing = true + log.Critical("Missing pin parameter") + fallthrough + case len(*token) == 0: + missing = true + log.Critical("Missing token parameter") + fallthrough + case len(*label) == 0: + missing = true + log.Critical("Missing label parameter") + } + if missing { + log.Critical("All flags must be provided, bitch.") + flag.Usage() + return + } + + // Read the issuer cert + certPEM, err := ioutil.ReadFile(*certFile) + if err != nil { + log.Criticalf("Unable to read certificate: %v", err) + return + } + + certBlock, _ := pem.Decode(certPEM) + cert, err := x509.ParseCertificate(certBlock.Bytes) + if err != nil { + log.Criticalf("Unable to parse certificate: %v", err) + return + } + + // Read the list of revoked certs + jsonConfig, err := ioutil.ReadFile(*listFile) + if err != nil { + log.Criticalf("Unable to read list of revoked certs: %v", err) + return + } + + var config Config + err = json.Unmarshal(jsonConfig, &config) + if err != nil { + log.Criticalf("Unable to parse list of revoked certs: %v", err) + return + } + + // Set up PKCS#11 key + priv, err := pkcs11key.New(*module, *token, *pin, *label) + if err != nil { + log.Criticalf("Unable to instantiate PKCS#11 private key: %v", err) + return + } + + // Sign the CRL + crlDER, err := cert.CreateCRL(rand.Reader, priv, config.RevokedCerts, config.ThisUpdate, config.NextUpdate) + if err != nil { + log.Criticalf("Error signing certificate: %v", err) + return + } + + fmt.Println(string(pem.EncodeToMemory(&pem.Block{ + Type: "X509 CRL", + Bytes: crlDER, + }))) +} diff --git a/cmd/mkroot/main.go b/cmd/mkroot/main.go new file mode 100644 index 000000000..133212be0 --- /dev/null +++ b/cmd/mkroot/main.go @@ -0,0 +1,148 @@ +package main + +import ( + "crypto/rand" + "crypto/sha1" + "crypto/x509" + "crypto/x509/pkix" + "encoding/json" + "encoding/pem" + "flag" + "fmt" + "io/ioutil" + "math/big" + "time" + + "github.com/cloudflare/cfssl/crypto/pkcs11key" + "github.com/cloudflare/cfssl/log" +) + +var configFile = flag.String("config", "", "JSON file for subject and validity") +var module = flag.String("pkcs11-module", "", "PKCS#11 module") +var pin = flag.String("pkcs11-pin", "", "PKCS#11 password") +var token = flag.String("pkcs11-token", "", "PKCS#11 token name") +var label = flag.String("pkcs11-label", "", "PKCS#11 key label") + +type Config struct { + Name struct { + C string + O string + OU string + CN string + } + NotBefore time.Time + NotAfter time.Time +} + +func main() { + // Validate input + // All flags are required + flag.Parse() + missing := false + switch { + case len(*configFile) == 0: + missing = true + log.Critical("Missing config parameter") + fallthrough + case len(*module) == 0: + missing = true + log.Critical("Missing module parameter") + fallthrough + case len(*pin) == 0: + missing = true + log.Critical("Missing pin parameter") + fallthrough + case len(*token) == 0: + missing = true + log.Critical("Missing token parameter") + fallthrough + case len(*label) == 0: + missing = true + log.Critical("Missing label parameter") + } + if missing { + log.Critical("All flags must be provided, bitch.") + flag.Usage() + return + } + + jsonConfig, err := ioutil.ReadFile(*configFile) + if err != nil { + log.Criticalf("Unable to read config: %v", err) + return + } + + var config Config + err = json.Unmarshal(jsonConfig, &config) + if err != nil { + log.Criticalf("Unable to parse config: %v", err) + return + } + + if len(config.Name.C) == 0 || len(config.Name.O) == 0 || + len(config.Name.CN) == 0 { + log.Criticalf("Config must provide country, organizationName, and commonName") + return + } + + if config.NotBefore.After(config.NotAfter) { + log.Criticalf("Invalid validity: notAfter is before notBefore") + return + } + + // Set up PKCS#11 key + priv, err := pkcs11key.New(*module, *token, *pin, *label) + if err != nil { + log.Criticalf("Unable to instantiate PKCS#11 private key: %v", err) + return + } + pub := priv.Public() + + // Generate serial number + serialLimit := new(big.Int).Lsh(big.NewInt(1), 128) + serialNumber, err := rand.Int(rand.Reader, serialLimit) + if err != nil { + log.Criticalf("Error generating serial number: %v", err) + return + } + + // Generate subject key ID + pubDER, err := x509.MarshalPKIXPublicKey(pub) + if err != nil { + log.Criticalf("Error generating serial number: %v", err) + return + } + h := sha1.New() + h.Write(pubDER) + keyID := h.Sum(nil) + + // Sign the certificate + rootTemplate := &x509.Certificate{ + SignatureAlgorithm: x509.SHA256WithRSA, + + SerialNumber: serialNumber, + Subject: pkix.Name{ + Country: []string{config.Name.C}, + Organization: []string{config.Name.O}, + CommonName: config.Name.CN, + }, + NotBefore: config.NotBefore, + NotAfter: config.NotAfter, + + BasicConstraintsValid: true, + IsCA: true, + + SubjectKeyId: keyID, + } + + rootDER, err := x509.CreateCertificate(rand.Reader, rootTemplate, rootTemplate, pub, priv) + if err != nil { + log.Criticalf("Error signing certificate: %v", err) + return + } + + fmt.Println(string(pem.EncodeToMemory(&pem.Block{ + Type: "CERTIFICATE", + Bytes: rootDER, + }))) +}