diff options
Diffstat (limited to 'create_cert.go')
-rw-r--r-- | create_cert.go | 195 |
1 files changed, 195 insertions, 0 deletions
diff --git a/create_cert.go b/create_cert.go new file mode 100644 index 0000000..d47732a --- /dev/null +++ b/create_cert.go @@ -0,0 +1,195 @@ +package main + +import ( + "crypto/x509" + "flag" + "fmt" + "math/big" + "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, + } +) + +func CreateCert(args []string) error { + var ( + flagUsageTemplate string + flagKeyUsage string + flagKeyExtUsage stringList + flagNotBefore string + flagNotAfter string + flagSerial int64 + flagLength int + flagIsCA bool + flagCA string + flagPrivate string + flagCSR string + flagOutput string + ) + fs := flag.NewFlagSet("pkictl create-cert", flag.ExitOnError) + fs.StringVar(&flagPrivate, "private-key", "", "the private key to generate the request") + fs.StringVar(&flagCSR, "sign-request", "", "the certificate sign request") + fs.StringVar(&flagOutput, "output", "stdout", "path to the output file (default stdout)") + fs.BoolVar(&flagIsCA, "is-ca", false, "is the result a CA - when true ca is ignored") + fs.StringVar(&flagUsageTemplate, "usage", "", "templates for usage (all, server, client)") + fs.StringVar(&flagKeyUsage, "key-usage", "", "comma separated list of key usages") + fs.Var(&flagKeyExtUsage, "key-ext-usage", "comma separated list of further usages") + fs.Int64Var(&flagSerial, "serial", 0, "the serial for the issued certificate") + fs.IntVar(&flagLength, "length", 0, "the number of sub CAs allowed (-1 equals no limit)") + fs.StringVar(&flagCA, "ca", "", "path to the CA certificate") + fs.StringVar( + &flagNotBefore, + "not-before", + time.Now().Format(time.RFC3339), + "time before the certificate is not valid in RFC3339 format (default now)", + ) + fs.StringVar( + &flagNotAfter, + "not-after", + time.Now().Format(time.RFC3339), + "time after the certificate is not valid in RFC3339 format (default now)", + ) + fs.Parse(args) + + if flagPrivate == "" { + return fmt.Errorf("missing private key") + } + if flagCSR == "" { + return fmt.Errorf("missing certificate sign request") + } + + out, err := openOutput(flagOutput) + if err != nil { + return err + } + // FIXME check all other out.Close for stdout exception + if flagOutput != "stdout" { + defer out.Close() + } + pk, err := loadPrivateKey(flagPrivate) + if err != nil { + return err + } + csr, err := parseCSR(flagCSR) + if err != nil { + return err + } + var ca *pki.Certificate + if !flagIsCA { + ca, err = parseCA(flagCA) + if err != nil { + return err + } + } + + notBefore, err := time.Parse(time.RFC3339, flagNotBefore) + if err != nil { + return err + } + notAfter, err := time.Parse(time.RFC3339, flagNotAfter) + if err != nil { + return err + } + if notBefore.After(notAfter) { + return fmt.Errorf("before and after range is wrong") + } + cert_opts := pki.CertificateOptions{ + SerialNumber: big.NewInt(flagSerial), + NotBefore: notBefore, + NotAfter: notAfter, + IsCA: flagIsCA, + CALength: flagLength, + } + if flagKeyUsage != "" { + keyUsage, found := ValidKeyUsages[flagKeyUsage] + if !found { + return fmt.Errorf("unknown key usage") + } + cert_opts.KeyUsage = keyUsage + } + + for pos, name := range flagKeyExtUsage { + if val, found := ValidExtKeyUsages[name]; !found { + return fmt.Errorf("%d ext key usage '%s' unknown", pos, name) + } else { + cert_opts.KeyExtendedUsage = append(cert_opts.KeyExtendedUsage, val) + } + } + + cert, err := csr.ToCertificate(pk, cert_opts, ca) + if err != nil { + return err + } + return writePem(cert, out) +} + +func parseCSR(path string) (*pki.CertificateRequest, error) { + pems_raw, err := openInput(path) + if err != nil { + return nil, err + } + defer pems_raw.Close() + pems, err := parseFile(pems_raw) + if err != nil { + return nil, err + } + csr_raw, err := getSectionFromPem(pems, pki.PemLabelCertificateRequest) + if err != nil { + return nil, err + } + csr, err := pki.LoadCertificateSignRequest(csr_raw) + if err != nil { + return nil, err + } + return csr, nil +} + +func parseCA(path string) (*pki.Certificate, error) { + pems_raw, err := openInput(path) + if err != nil { + return nil, err + } + defer pems_raw.Close() + pems, err := parseFile(pems_raw) + if err != nil { + return nil, err + } + ca_raw, err := getSectionFromPem(pems, pki.PemLabelCertificate) + if err != nil { + return nil, err + } + ca, err := pki.LoadCertificate(ca_raw) + if err != nil { + return nil, err + } + return ca, nil +} |