Skip to content

joemiller/certin

Repository files navigation

certin

ci-cd Go Doc

Certin is a Go library and CLI for quickly creating keys and certificates for use as test fixtures.

It is available as both a Go library for use in Go tests as well as a CLI for creating fixtures as files for Go or any other language.

CLI

Install

Available options:

  • Go 1.16+: go install github.com/joemiller/certin/cmd/certin@latest
  • macOS homebrew (Linuxbrew might work too): brew install joemiller/taps/certin
  • Binaries for all platforms (macOS, Linux, *BSD) on GitHub Releases
  • Docker images

Usage:

$ certin create KEY CERT

Flags:
      --bundle string        (optional) Create combined bundle FILE containing private-key, certificate, and signing CA cert
      --cn string            common name
      --csr                  create a Certificate Signing Request (CSR) instead of a signed certificate
  -d, --duration string      certificate duration. Examples of valid values: 1w, 1d, 2d3h5m, 1h30m, 10s (default "1y")
  -h, --help                 help for create
      --is-ca                create a CA cert capable of signing other certs
  -K, --key-type string      key type to create (rsa-2048, rsa-3072, rsa-4096, ecdsa-256, ecdsa-384, ecdsa-512, ed25519) (default "rsa-2048")
      --o strings            organization
      --ou strings           organizational unit
      --sans strings         SubjectAltNames, comma separated
  -c, --signer-cert string   CA cert to sign the CERT with. If omitted, a self-signed cert is generated.
  -k, --signer-key string    CA key to sign the CERT with. If omitted, a self-signed cert is generated.

Examples:

  • self-signed cert:
certin create self-signed.key self-signed.crt
  • root CA:
certin create root.key root.crt --is-ca=true
  • intermediate CA:
certin create intermediate.key intermediate.crt \
  --signer-key root.key \
  --signer-cert root.crt \
  --is-ca
  • leaf cert with SubjectAltNames (SANs):
certin create example.key example.crt \
  --signer-key intermediate.key \
  --signer-cert intermediate.crt \
  --cn example.com \
  --sans "example.com,www.example.com" \
  --key-type "ecdsa-256"
  • Generate certificate signing request (CSR) instead of a signed certificate:
certin create example.key example.csr --cn example.com

Go Library

go get -u github.com/joemiller/certin

Example uses:

// See certin.go or the godoc page for details on each struct member
type Request struct {
	CN       string
	O        []string
	OU       []string
	SANs     []string
	Duration time.Duration
	IsCA     bool
	KeyType  string
}

type KeyAndCert struct {
	Certificate *x509.Certificate
	PrivateKey  crypto.PrivateKey
	PublicKey   crypto.PublicKey
}

type KeyAndCSR struct {
	CertificateRequest *x509.CertificateRequest
	PrivateKey         crypto.PrivateKey
	PublicKey          crypto.PublicKey
}
  • simple self-signed cert:
// the first param to NewCert is the parent (signing) CA cert. nil creates a self-signed cert
// the returned value is a certin.KeyAndCert
root, err := certin.NewCert(nil, certin.Request{CN: "self-signed"}))
  • root CA cert:
root, err := certin.NewCert(nil, certin.Request{CN: "root CA", IsCA: true})
  • root and intermediate CA certs:
root, err := certin.NewCert(nil, Request{CN: "root", IsCA: true})
// pass the root key/cert to NewCert() to sign the intermediate cert
interm, err := certin.NewCert(root, Request{CN: " intermediate", IsCA: true})
  • leaf certificate signed by intermediate:
leaf, err := certin.NewCert(interm, Request{CN: "example.com", SANs: []string{"example.com", "www.example.com"}})

If you need more control over the contents of the certificate you can create a cert from a x509.Certificate template instead of certin.Request. This allows for full control over the contents of the cert.

templ := &x509.Certificate{
  SerialNumber: big.NewInt(123456789),
  Subject: pkix.Name{
    Organization:       []string{"My Org"},
    OrganizationalUnit: []string{"My dept"},
    CommonName:         "example.com",
  },
  DNSNames: []string{"example.com"}

  NotBefore: time.Now(),
  NotAfter:  time.Now().Add(10 * time.Minute),
	KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature
}
cert, err := certin.NewCertFromX509Template(interm, "ecdsa-256", templ)
  • Generate certificate signing request (CSR) instead of a signed certificate:
keyAndCSR, err := certin.NewCSR(Request{CN: "example.com", SANs: []string{"example.com", "www.example.com"}})

Motivation

I've worked on lots of projects that involved TLS certs and found myself constantly needing to create certificate hiearchies for test fixtures. There are plenty of great tools that can accomplish this. After experimenting with a few of them I decided I wanted something simpler and built specifically for the simplest test cases.

  • openssl: Plenty capable of being scripted to create root and intermediate CAs and sign certs. However you usually end up with some mixture of openssl.cnf files to express certain options in combination with command line flags.
  • cfssl: Very flexible, easy to install and use. Most config is done through JSON files.

I felt like the common cases for certs needed during testing should be generatable with a simple CLI and only a few command flags and common defaults, no config files or complex scripts.