command line tool to make self signed x.509 CA and cert for a domain
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

176 lines
4.4 KiB

package main
import (
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"fmt"
"log"
"os"
"path/filepath"
"time"
"git.sequentialread.com/forest/easypki.git/pkg/certificate"
"git.sequentialread.com/forest/easypki.git/pkg/easypki"
"git.sequentialread.com/forest/easypki.git/pkg/store"
errors "git.sequentialread.com/forest/pkg-errors"
)
func main() {
domain := os.Args[1]
outputLocation, err := os.Getwd()
if err != nil {
log.Fatal(err)
}
inMemoryStore := &store.InMemory{}
pki := &easypki.EasyPKI{Store: inMemoryStore}
domainCA := fmt.Sprintf("%s_CA", domain)
log.Println("make-fake-cert: creating server CA / key pair ")
// Create a CA for the server's key/cert
err = pki.Sign(
nil,
&easypki.Request{
Name: domainCA,
Template: &x509.Certificate{
NotAfter: time.Now().Add(time.Hour * 24 * 720),
IsCA: true,
MaxPathLen: -1,
Subject: getSubject(domainCA),
},
},
)
if err != nil {
panic(errors.Wrap(err, "make-fake-cert: failed creating CA"))
}
err = saveBundle(pki, domainCA, domainCA, false, outputLocation)
if err != nil {
panic(errors.Wrap(err, "make-fake-cert: saveBundle():"))
}
caSigner, err := pki.GetCA(domainCA)
if err != nil {
panic(errors.Wrap(err, "make-fake-cert: signer named \"CA\" was not found"))
}
// Create server certificate
err = pki.Sign(
caSigner,
&easypki.Request{
Name: domain,
Template: &x509.Certificate{
NotAfter: time.Now().Add(time.Hour * 24 * 720),
IsCA: false,
Subject: getSubject(domain),
DNSNames: []string{domain},
},
},
)
if err != nil {
panic(errors.Wrap(err, "make-fake-cert: failed creating Threshold server certificate"))
}
err = saveBundle(pki, domainCA, domain, true, outputLocation)
if err != nil {
panic(errors.Wrap(err, "make-fake-cert: saveBundle():"))
}
if len(os.Args) == 3 {
user := fmt.Sprintf("%s@%s", os.Args[2], domain)
// Create client certificate
err = pki.Sign(
caSigner,
&easypki.Request{
Name: user,
Template: &x509.Certificate{
NotAfter: time.Now().Add(time.Hour * 24 * 720),
IsCA: false,
Subject: getSubject(user),
EmailAddresses: []string{user},
},
},
)
if err != nil {
panic(errors.Wrap(err, "make-fake-cert: failed creating Threshold server certificate"))
}
err = saveBundle(pki, domainCA, user, true, outputLocation)
if err != nil {
panic(errors.Wrap(err, "make-fake-cert: saveBundle():"))
}
}
}
func saveBundle(pki *easypki.EasyPKI, caName, bundleName string, savePrivateKey bool, saveInDirectory string) error {
var bundle *certificate.Bundle
if caName == "" {
caName = bundleName
}
bundle, err := pki.GetBundle(caName, bundleName)
if err != nil {
panic(errors.Wrapf(err, "Failed getting bundle %v within CA %v: %v", bundleName, caName))
}
leaf := bundle
chain := []*certificate.Bundle{bundle}
//if fullChain {
for {
if leaf.Cert.Issuer.CommonName == leaf.Cert.Subject.CommonName {
break
}
ca, err := pki.GetCA(leaf.Cert.Issuer.CommonName)
if err != nil {
panic(errors.Wrapf(err, "Failed getting signing CA %v: %v", leaf.Cert.Issuer.CommonName))
}
chain = append(chain, ca)
leaf = ca
}
//}
if savePrivateKey {
key, err := os.Create(filepath.Join(saveInDirectory, bundleName+".key"))
if err != nil {
panic(errors.Wrap(err, "Failed creating key output file"))
}
if err := pem.Encode(key, &pem.Block{
Bytes: x509.MarshalPKCS1PrivateKey(bundle.Key),
Type: "RSA PRIVATE KEY",
}); err != nil {
panic(errors.Wrap(err, "Failed ecoding private key"))
}
}
crtName := bundleName + ".crt"
cert, err := os.Create(filepath.Join(saveInDirectory, crtName))
if err != nil {
panic(errors.Wrap(err, "Failed creating chain output file"))
}
for _, c := range chain {
if err := pem.Encode(cert, &pem.Block{
Bytes: c.Cert.Raw,
Type: "CERTIFICATE",
}); err != nil {
panic(errors.Wrapf(err, "Failed ecoding %v certificate: %v", c.Name))
}
}
return nil
}
// TODO add certificate metadata option to seedpacket?
func getSubject(commonName string) pkix.Name {
return pkix.Name{
Organization: []string{"aaaaa user left blank"},
OrganizationalUnit: []string{"aaaaa user left blank"},
Locality: []string{"aaaaa user left blank"},
Country: []string{"aaaaa user left blank"},
Province: []string{"aaaaa user left blank"},
CommonName: commonName,
}
}