split certificate stuff into own file
This moves the complicated certificate flag handling into its own file to make it a bit easier to handle.
This commit is contained in:
parent
9ba6a88449
commit
37423989c8
|
@ -0,0 +1,239 @@
|
|||
package main
|
||||
|
||||
// This file contains all code to create certificates.
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gibheer/pki"
|
||||
)
|
||||
|
||||
var (
|
||||
// the possible valid key usages to check against the commandline
|
||||
ValidKeyUsages = map[string]x509.KeyUsage{
|
||||
"digitalsignature": x509.KeyUsageDigitalSignature,
|
||||
"contentcommitment": x509.KeyUsageContentCommitment,
|
||||
"keyencipherment": x509.KeyUsageKeyEncipherment,
|
||||
"dataencipherment": x509.KeyUsageDataEncipherment,
|
||||
"keyagreement": x509.KeyUsageKeyAgreement,
|
||||
"certsign": x509.KeyUsageCertSign,
|
||||
"crlsign": x509.KeyUsageCRLSign,
|
||||
"encipheronly": x509.KeyUsageEncipherOnly,
|
||||
"decipheronly": x509.KeyUsageDecipherOnly,
|
||||
}
|
||||
// the valid extended key usages, to check against the commandline
|
||||
ValidExtKeyUsages = map[string]x509.ExtKeyUsage{
|
||||
"any": x509.ExtKeyUsageAny,
|
||||
"serverauth": x509.ExtKeyUsageServerAuth,
|
||||
"clientauth": x509.ExtKeyUsageClientAuth,
|
||||
"codesigning": x509.ExtKeyUsageCodeSigning,
|
||||
"emailprotection": x509.ExtKeyUsageEmailProtection,
|
||||
"ipsecendsystem": x509.ExtKeyUsageIPSECEndSystem,
|
||||
"ipsectunnel": x509.ExtKeyUsageIPSECTunnel,
|
||||
"ipsecuser": x509.ExtKeyUsageIPSECUser,
|
||||
"timestamping": x509.ExtKeyUsageTimeStamping,
|
||||
"ocspsigning": x509.ExtKeyUsageOCSPSigning,
|
||||
"microsoftservergatedcrypto": x509.ExtKeyUsageMicrosoftServerGatedCrypto,
|
||||
"netscapeservergatedcrypto": x509.ExtKeyUsageNetscapeServerGatedCrypto,
|
||||
}
|
||||
|
||||
CmdCreateCert = &Command{
|
||||
Use: "create-cert",
|
||||
Short: "create a certificate from a sign request",
|
||||
Long: "Create a certificate based on a certificate sign request.",
|
||||
Example: "create-cert -private-key=foo.ecdsa -csr-path=foo.csr",
|
||||
Run: create_cert,
|
||||
}
|
||||
// certificate specific creation stuff
|
||||
FlagCertificateGeneration pki.CertificateOptions
|
||||
)
|
||||
|
||||
type (
|
||||
// holds all certificate related flags, which need parsing afterwards
|
||||
certiticateRequestRawFlags struct {
|
||||
manual struct {
|
||||
serialNumber string // the serial number for the cert
|
||||
commonName string // the common name used in the cert
|
||||
dnsNames string // all alternative names in the certificate (comma separated list)
|
||||
ipAddresses string // all IP addresses in the certificate (comma separated list)
|
||||
emailAddresses string // alternative email addresses
|
||||
}
|
||||
automatic struct {
|
||||
Country string // the country names which should end up in the cert (comma separated list)
|
||||
Organization string // the organization names (comma separated list)
|
||||
OrganizationalUnit string // the organizational units (comma separated list)
|
||||
Locality string // the city or locality (comma separated list)
|
||||
Province string // the province name (comma separated list)
|
||||
StreetAddress string // the street addresses of the organization (comma separated list)
|
||||
PostalCode string // the postal codes of the locality
|
||||
}
|
||||
}
|
||||
|
||||
// the raw flags collected through flags
|
||||
certGenerationRaw struct {
|
||||
serial int64
|
||||
notBefore string
|
||||
notAfter string
|
||||
isCA bool
|
||||
length int
|
||||
caPath string // path to the ca file if isCA is false
|
||||
keyUsage string // comma separated list of key usages
|
||||
extKeyUsage string // comma separated list of extended key usages
|
||||
}
|
||||
)
|
||||
|
||||
// add flag to load certificate flags
|
||||
func InitFlagCert(cmd *Command) {
|
||||
cmd.Flags().Int64Var(&flagContainer.certGeneration.serial, "serial", 0, "serial number of all certificates")
|
||||
cmd.Flags().BoolVar(&flagContainer.certGeneration.isCA, "ca", false, "check if the resulting certificate is a ca")
|
||||
cmd.Flags().IntVar(
|
||||
&flagContainer.certGeneration.
|
||||
length,
|
||||
"length",
|
||||
0,
|
||||
"the number of certificates allowed in the chain between this cert and the end certificate",
|
||||
)
|
||||
cmd.Flags().StringVar(
|
||||
&flagContainer.certGeneration.notBefore,
|
||||
"not-before",
|
||||
time.Now().Format(time.RFC3339),
|
||||
"time before the certificate is not valid in RFC3339 format (default now)",
|
||||
)
|
||||
cmd.Flags().StringVar(
|
||||
&flagContainer.certGeneration.notAfter,
|
||||
"not-after",
|
||||
time.Now().Add(time.Duration(180*24*time.Hour)).Format(time.RFC3339),
|
||||
"time after which the certificate is not valid in RFC3339 format (default now + 180 days)",
|
||||
)
|
||||
cmd.Flags().StringVar(
|
||||
&flagContainer.certGeneration.keyUsage,
|
||||
"key-usage", "",
|
||||
"comma separated list of key usages",
|
||||
)
|
||||
cmd.Flags().StringVar(
|
||||
&flagContainer.certGeneration.extKeyUsage,
|
||||
"ext-key-usage", "",
|
||||
"comma separated list of extended key usage flags",
|
||||
)
|
||||
}
|
||||
|
||||
// create a certificate
|
||||
func create_cert(cmd *Command, args []string) {
|
||||
err := checkFlags(checkPrivateKey, checkOutput, checkCSR, checkCertFlags)
|
||||
if err != nil {
|
||||
crash_with_help(cmd, ErrorFlagInput, "Flags invalid: %s", err)
|
||||
}
|
||||
|
||||
// TODO implement flags for all certificate options
|
||||
cert, err := FlagCertificateSignRequest.ToCertificate(
|
||||
FlagPrivateKey,
|
||||
FlagCertificateGeneration,
|
||||
nil,
|
||||
)
|
||||
if err != nil {
|
||||
crash_with_help(cmd, ErrorProgram, "Error generating certificate: %s", err)
|
||||
}
|
||||
pem_block, err := cert.MarshalPem()
|
||||
if err != nil {
|
||||
crash_with_help(cmd, ErrorProgram, "Error when marshalling to pem: %s", err)
|
||||
}
|
||||
_, err = pem_block.WriteTo(FlagOutput)
|
||||
if err != nil {
|
||||
crash_with_help(cmd, ErrorProgram, "Could not write to output: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
// parse the certificate data
|
||||
func checkCertFlags() error {
|
||||
FlagCertificateGeneration.IsCA = flagContainer.certGeneration.isCA
|
||||
FlagCertificateGeneration.CALength = flagContainer.certGeneration.length
|
||||
FlagCertificateGeneration.SerialNumber = big.NewInt(flagContainer.certGeneration.serial)
|
||||
|
||||
var err error
|
||||
if notbefore := flagContainer.certGeneration.notBefore; notbefore != "" {
|
||||
FlagCertificateGeneration.NotBefore, err = parseTimeRFC3339(notbefore)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if notafter := flagContainer.certGeneration.notAfter; notafter != "" {
|
||||
FlagCertificateGeneration.NotAfter, err = parseTimeRFC3339(notafter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// parse the key usage string
|
||||
if keyUstr := flagContainer.certGeneration.keyUsage; keyUstr != "" {
|
||||
keyUarr := strings.Split(keyUstr, ",")
|
||||
var keyUresult x509.KeyUsage
|
||||
for _, usage := range keyUarr {
|
||||
if value, ok := ValidKeyUsages[strings.ToLower(usage)]; ok {
|
||||
keyUresult = keyUresult | value
|
||||
} else {
|
||||
return fmt.Errorf("unsupported key usage '%s'", usage)
|
||||
}
|
||||
}
|
||||
FlagCertificateGeneration.KeyUsage = keyUresult
|
||||
}
|
||||
// parse the extended key usage flags
|
||||
if eKeyUstr := flagContainer.certGeneration.extKeyUsage; eKeyUstr != "" {
|
||||
eKeyUarr := strings.Split(eKeyUstr, ",")
|
||||
eKeyUResult := make([]x509.ExtKeyUsage, 0)
|
||||
for _, usage := range eKeyUarr {
|
||||
if value, ok := ValidExtKeyUsages[strings.ToLower(usage)]; ok {
|
||||
eKeyUResult = append(eKeyUResult, value)
|
||||
} else {
|
||||
return fmt.Errorf("unsupported extended key usage '%s'", usage)
|
||||
}
|
||||
}
|
||||
FlagCertificateGeneration.KeyExtendedUsage = eKeyUResult
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// add flag to load certificate sign request
|
||||
func InitFlagCSR(cmd *Command) {
|
||||
cmd.Flags().StringVar(&flagContainer.signRequestPath, "csr-path", "", "path to the certificate sign request")
|
||||
}
|
||||
|
||||
// parse the certificate sign request
|
||||
func checkCSR() error {
|
||||
rest, err := ioutil.ReadFile(flagContainer.signRequestPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error reading certificate sign request: %s", err)
|
||||
}
|
||||
|
||||
var csr_asn1 []byte
|
||||
var block *pem.Block
|
||||
for len(rest) > 0 {
|
||||
block, rest = pem.Decode(rest)
|
||||
if block.Type == "CERTIFICATE REQUEST" {
|
||||
csr_asn1 = block.Bytes
|
||||
break
|
||||
}
|
||||
}
|
||||
if len(csr_asn1) == 0 {
|
||||
return fmt.Errorf(
|
||||
"No certificate sign request found in %s",
|
||||
flagContainer.signRequestPath,
|
||||
)
|
||||
}
|
||||
|
||||
csr, err := pki.LoadCertificateSignRequest(csr_asn1)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Invalid certificate sign request: %s", err)
|
||||
}
|
||||
FlagCertificateSignRequest = csr
|
||||
return nil
|
||||
}
|
||||
|
||||
// parse the string as a RFC3339 time
|
||||
func parseTimeRFC3339(tr string) (time.Time, error) {
|
||||
return time.Parse(time.RFC3339, tr)
|
||||
}
|
201
flags.go
201
flags.go
|
@ -4,74 +4,18 @@ package main
|
|||
// often used by multiple functions.
|
||||
|
||||
import (
|
||||
"crypto/elliptic"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"net"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gibheer/pki"
|
||||
)
|
||||
|
||||
var (
|
||||
// the possible valid key usages to check against the commandline
|
||||
ValidKeyUsages = map[string]x509.KeyUsage{
|
||||
"digitalsignature": x509.KeyUsageDigitalSignature,
|
||||
"contentcommitment": x509.KeyUsageContentCommitment,
|
||||
"keyencipherment": x509.KeyUsageKeyEncipherment,
|
||||
"dataencipherment": x509.KeyUsageDataEncipherment,
|
||||
"keyagreement": x509.KeyUsageKeyAgreement,
|
||||
"certsign": x509.KeyUsageCertSign,
|
||||
"crlsign": x509.KeyUsageCRLSign,
|
||||
"encipheronly": x509.KeyUsageEncipherOnly,
|
||||
"decipheronly": x509.KeyUsageDecipherOnly,
|
||||
}
|
||||
// the valid extended key usages, to check against the commandline
|
||||
ValidExtKeyUsages = map[string]x509.ExtKeyUsage{
|
||||
"any": x509.ExtKeyUsageAny,
|
||||
"serverauth": x509.ExtKeyUsageServerAuth,
|
||||
"clientauth": x509.ExtKeyUsageClientAuth,
|
||||
"codesigning": x509.ExtKeyUsageCodeSigning,
|
||||
"emailprotection": x509.ExtKeyUsageEmailProtection,
|
||||
"ipsecendsystem": x509.ExtKeyUsageIPSECEndSystem,
|
||||
"ipsectunnel": x509.ExtKeyUsageIPSECTunnel,
|
||||
"ipsecuser": x509.ExtKeyUsageIPSECUser,
|
||||
"timestamping": x509.ExtKeyUsageTimeStamping,
|
||||
"ocspsigning": x509.ExtKeyUsageOCSPSigning,
|
||||
"microsoftservergatedcrypto": x509.ExtKeyUsageMicrosoftServerGatedCrypto,
|
||||
"netscapeservergatedcrypto": x509.ExtKeyUsageNetscapeServerGatedCrypto,
|
||||
}
|
||||
)
|
||||
|
||||
type (
|
||||
// holds all certificate related flags, which need parsing afterwards
|
||||
certiticateRequestRawFlags struct {
|
||||
manual struct {
|
||||
serialNumber string // the serial number for the cert
|
||||
commonName string // the common name used in the cert
|
||||
dnsNames string // all alternative names in the certificate (comma separated list)
|
||||
ipAddresses string // all IP addresses in the certificate (comma separated list)
|
||||
emailAddresses string // alternative email addresses
|
||||
}
|
||||
automatic struct {
|
||||
Country string // the country names which should end up in the cert (comma separated list)
|
||||
Organization string // the organization names (comma separated list)
|
||||
OrganizationalUnit string // the organizational units (comma separated list)
|
||||
Locality string // the city or locality (comma separated list)
|
||||
Province string // the province name (comma separated list)
|
||||
StreetAddress string // the street addresses of the organization (comma separated list)
|
||||
PostalCode string // the postal codes of the locality
|
||||
}
|
||||
}
|
||||
|
||||
// a container go gather all incoming flags for further processing
|
||||
paramContainer struct {
|
||||
outputPath string // path to output whatever is generated
|
||||
|
@ -87,17 +31,6 @@ type (
|
|||
certificatePath string // path to a certificate
|
||||
}
|
||||
|
||||
certGenerationRaw struct {
|
||||
serial int64
|
||||
notBefore string
|
||||
notAfter string
|
||||
isCA bool
|
||||
length int
|
||||
caPath string // path to the ca file if isCA is false
|
||||
keyUsage string // comma separated list of key usages
|
||||
extKeyUsage string // comma separated list of extended key usages
|
||||
}
|
||||
|
||||
flagCheck func() error
|
||||
)
|
||||
|
||||
|
@ -140,14 +73,6 @@ certificate requests and certificates and sign/verify messages.`,
|
|||
Run: create_sign_request,
|
||||
}
|
||||
|
||||
CmdCreateCert = &Command{
|
||||
Use: "create-cert",
|
||||
Short: "create a certificate from a sign request",
|
||||
Long: "Create a certificate based on a certificate sign request.",
|
||||
Example: "create-cert -private-key=foo.ecdsa -csr-path=foo.csr",
|
||||
Run: create_cert,
|
||||
}
|
||||
|
||||
// variable to hold the raw arguments before checking
|
||||
flagContainer *paramContainer
|
||||
|
||||
|
@ -165,8 +90,6 @@ certificate requests and certificates and sign/verify messages.`,
|
|||
FlagCertificateRequestData *pki.CertificateData
|
||||
// the certificate sign request
|
||||
FlagCertificateSignRequest *pki.CertificateRequest
|
||||
// certificate specific creation stuff
|
||||
FlagCertificateGeneration pki.CertificateOptions
|
||||
)
|
||||
|
||||
func InitFlags() {
|
||||
|
@ -234,129 +157,7 @@ func checkPublicKey() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// add flag to load certificate flags
|
||||
func InitFlagCert(cmd *Command) {
|
||||
cmd.Flags().Int64Var(&flagContainer.certGeneration.serial, "serial", 0, "serial number of all certificates")
|
||||
cmd.Flags().BoolVar(&flagContainer.certGeneration.isCA, "ca", false, "check if the resulting certificate is a ca")
|
||||
cmd.Flags().IntVar(
|
||||
&flagContainer.certGeneration.
|
||||
length,
|
||||
"length",
|
||||
0,
|
||||
"the number of certificates allowed in the chain between this cert and the end certificate",
|
||||
)
|
||||
cmd.Flags().StringVar(
|
||||
&flagContainer.certGeneration.notBefore,
|
||||
"not-before",
|
||||
time.Now().Format(time.RFC3339),
|
||||
"time before the certificate is not valid in RFC3339 format (default now)",
|
||||
)
|
||||
cmd.Flags().StringVar(
|
||||
&flagContainer.certGeneration.notAfter,
|
||||
"not-after",
|
||||
time.Now().Add(time.Duration(180*24*time.Hour)).Format(time.RFC3339),
|
||||
"time after which the certificate is not valid in RFC3339 format (default now + 180 days)",
|
||||
)
|
||||
cmd.Flags().StringVar(
|
||||
&flagContainer.certGeneration.keyUsage,
|
||||
"key-usage", "",
|
||||
"comma separated list of key usages",
|
||||
)
|
||||
cmd.Flags().StringVar(
|
||||
&flagContainer.certGeneration.extKeyUsage,
|
||||
"ext-key-usage", "",
|
||||
"comma separated list of extended key usage flags",
|
||||
)
|
||||
}
|
||||
|
||||
// parse the certificate data
|
||||
func checkCertFlags() error {
|
||||
FlagCertificateGeneration.IsCA = flagContainer.certGeneration.isCA
|
||||
FlagCertificateGeneration.CALength = flagContainer.certGeneration.length
|
||||
FlagCertificateGeneration.SerialNumber = big.NewInt(flagContainer.certGeneration.serial)
|
||||
|
||||
var err error
|
||||
if notbefore := flagContainer.certGeneration.notBefore; notbefore != "" {
|
||||
FlagCertificateGeneration.NotBefore, err = parseTimeRFC3339(notbefore)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if notafter := flagContainer.certGeneration.notAfter; notafter != "" {
|
||||
FlagCertificateGeneration.NotAfter, err = parseTimeRFC3339(notafter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// parse the key usage string
|
||||
if keyUstr := flagContainer.certGeneration.keyUsage; keyUstr != "" {
|
||||
keyUarr := strings.Split(keyUstr, ",")
|
||||
var keyUresult x509.KeyUsage
|
||||
for _, usage := range keyUarr {
|
||||
if value, ok := ValidKeyUsages[strings.ToLower(usage)]; ok {
|
||||
keyUresult = keyUresult | value
|
||||
} else {
|
||||
return fmt.Errorf("unsupported key usage '%s'", usage)
|
||||
}
|
||||
}
|
||||
FlagCertificateGeneration.KeyUsage = keyUresult
|
||||
}
|
||||
// parse the extended key usage flags
|
||||
if eKeyUstr := flagContainer.certGeneration.extKeyUsage; eKeyUstr != "" {
|
||||
eKeyUarr := strings.Split(eKeyUstr, ",")
|
||||
eKeyUResult := make([]x509.ExtKeyUsage, 0)
|
||||
for _, usage := range eKeyUarr {
|
||||
if value, ok := ValidExtKeyUsages[strings.ToLower(usage)]; ok {
|
||||
eKeyUResult = append(eKeyUResult, value)
|
||||
} else {
|
||||
return fmt.Errorf("unsupported extended key usage '%s'", usage)
|
||||
}
|
||||
}
|
||||
FlagCertificateGeneration.KeyExtendedUsage = eKeyUResult
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseTimeRFC3339(tr string) (time.Time, error) {
|
||||
return time.Parse(time.RFC3339, tr)
|
||||
}
|
||||
|
||||
// add flag to load certificate sign request
|
||||
func InitFlagCSR(cmd *Command) {
|
||||
cmd.Flags().StringVar(&flagContainer.signRequestPath, "csr-path", "", "path to the certificate sign request")
|
||||
}
|
||||
|
||||
// parse the certificate sign request
|
||||
func checkCSR() error {
|
||||
rest, err := ioutil.ReadFile(flagContainer.signRequestPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error reading certificate sign request: %s", err)
|
||||
}
|
||||
|
||||
var csr_asn1 []byte
|
||||
var block *pem.Block
|
||||
for len(rest) > 0 {
|
||||
block, rest = pem.Decode(rest)
|
||||
if block.Type == "CERTIFICATE REQUEST" {
|
||||
csr_asn1 = block.Bytes
|
||||
break
|
||||
}
|
||||
}
|
||||
if len(csr_asn1) == 0 {
|
||||
return fmt.Errorf(
|
||||
"No certificate sign request found in %s",
|
||||
flagContainer.signRequestPath,
|
||||
)
|
||||
}
|
||||
|
||||
csr, err := pki.LoadCertificateSignRequest(csr_asn1)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Invalid certificate sign request: %s", err)
|
||||
}
|
||||
FlagCertificateSignRequest = csr
|
||||
return nil
|
||||
}
|
||||
|
||||
// initialize the output flag
|
||||
func InitFlagOutput(cmd *Command) {
|
||||
cmd.Flags().StringVar(&flagContainer.outputPath, "output", "STDOUT", "path to the output or STDOUT")
|
||||
}
|
||||
|
|
25
main.go
25
main.go
|
@ -117,31 +117,6 @@ func create_sign_request(cmd *Command, args []string) {
|
|||
}
|
||||
}
|
||||
|
||||
func create_cert(cmd *Command, args []string) {
|
||||
err := checkFlags(checkPrivateKey, checkOutput, checkCSR, checkCertFlags)
|
||||
if err != nil {
|
||||
crash_with_help(cmd, ErrorFlagInput, "Flags invalid: %s", err)
|
||||
}
|
||||
|
||||
// TODO implement flags for all certificate options
|
||||
cert, err := FlagCertificateSignRequest.ToCertificate(
|
||||
FlagPrivateKey,
|
||||
FlagCertificateGeneration,
|
||||
nil,
|
||||
)
|
||||
if err != nil {
|
||||
crash_with_help(cmd, ErrorProgram, "Error generating certificate: %s", err)
|
||||
}
|
||||
pem_block, err := cert.MarshalPem()
|
||||
if err != nil {
|
||||
crash_with_help(cmd, ErrorProgram, "Error when marshalling to pem: %s", err)
|
||||
}
|
||||
_, err = pem_block.WriteTo(FlagOutput)
|
||||
if err != nil {
|
||||
crash_with_help(cmd, ErrorProgram, "Could not write to output: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
// crash and provide a helpful message
|
||||
func crash_with_help(cmd *Command, code int, message string, args ...interface{}) {
|
||||
fmt.Fprintf(os.Stderr, message+"\n", args...)
|
||||
|
|
Loading…
Reference in New Issue