Commit cb40b1b6 authored by Heiko Reese's avatar Heiko Reese
Browse files

* added new subcommand getpdf

* implemented --dry-run for newrequest
* switched to new soapclient instead of http.client
parent 67b9cc08
// Copyright © 2018 NAME HERE <EMAIL ADDRESS>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cmd
import (
"bytes"
"git.scc.kit.edu/KIT-CA/dfnpki"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"io/ioutil"
"log"
"strings"
"text/template"
)
var (
getPdfData struct {
RequestID string
RequestFile string
}
)
// getpdfCmd represents the getpdf command
var getpdfCmd = &cobra.Command{
Use: "getpdf",
Short: "Download pdf document for certificate request",
// Long: ``,
Run: func(cmd *cobra.Command, args []string) {
var (
RequestID string = "NONE"
filename string
)
viper.BindPFlags(cmd.PersistentFlags())
viper.Unmarshal(&getPdfData)
// handle --requestid
if viper.IsSet("requestid") {
RequestID = viper.GetString("requestid")
}
// handle --requestidfile
if viper.IsSet("requestidfile") {
content, err := ioutil.ReadFile(viper.GetString("requestidfile"))
if err != nil {
log.Fatal(err)
}
tokens := strings.Fields(string(content))
if len(tokens) < 1 {
log.Fatalf("No request id found in %s", viper.GetString("requestidfile"))
}
RequestID = strings.TrimSpace(tokens[0])
}
if RequestID == "NONE" {
log.Fatal("Please specify a request id")
}
// create http client
httpclient, err := dfnpki.GetHTTPClient()
if err != nil {
log.Fatal(err)
}
client := dfnpki.NewSoapClient(httpclient, dfnpki.GeneratePublicURL(viper.GetString("ca")))
// generate output filename
filenameTemplate, err := template.New("outfile").Parse(viper.GetString("outfile"))
if err != nil {
// last chance fallback…
filename = viper.GetString("outfile")
}
outfilewriter := bytes.Buffer{}
err = filenameTemplate.Execute(&outfilewriter, getPdfData)
if err != nil {
// last chance fallback…
filename = viper.GetString("outfile")
}
pdf, err := dfnpki.GetRequestPrintout(client, viper.GetInt("ra-id"), getPdfData.RequestID, viper.GetString("pin"))
if err != nil {
log.Fatalf("Unable to retrieve PDF: %s", err)
}
ioutil.WriteFile(filename, pdf, 0644)
if err != nil {
log.Fatalf("Unable to write PDF file »%s«: %s", filename, err)
}
log.Printf("PDF request saved to »%s«", filename)
},
}
func init() {
rootCmd.AddCommand(getpdfCmd)
getpdfCmd.PersistentFlags().SortFlags = false
getpdfCmd.PersistentFlags().StringVar(&getPdfData.RequestID, "requestid", "", "Request id (»Seriennummer«)")
getpdfCmd.PersistentFlags().StringVar(&getPdfData.RequestFile, "requestidfile", "", "File containing the request id (»Seriennummer«) on the first line")
getpdfCmd.MarkFlagFilename("requestidfile", "")
getpdfCmd.PersistentFlags().StringVarP(&cmdArguments.Outdir, "outfile", "o", "{{- .RequestID }}.pdf", "Directory for all output files")
getpdfCmd.PersistentFlags().StringVar(&cmdArguments.PIN, "pin", "", "Request PIN")
getpdfCmd.MarkFlagRequired("pin")
}
......@@ -25,16 +25,16 @@ import (
"crypto/x509"
"encoding/pem"
"path/filepath"
"net"
"net/url"
"path/filepath"
"bytes"
"git.scc.kit.edu/KIT-CA/dfnpki"
"github.com/kennygrant/sanitize"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"text/template"
"github.com/davecgh/go-spew/spew"
)
type sanGenerator struct {
......@@ -43,7 +43,7 @@ type sanGenerator struct {
}
// requestCmd represents the request command
var requestCmd *cobra.Command = &cobra.Command{
var requestCmd = &cobra.Command{
Use: "request",
Short: "Request a new certificate and retrieve the pdf application form",
// Long: ``,
......@@ -70,6 +70,7 @@ var requestCmd *cobra.Command = &cobra.Command{
if viper.GetString("cn") == "" {
log.Fatal("Please specify a common name (»CN«)")
}
// clean up CommonName
cnCleanUp := strings.NewReplacer("Ä", "Ae", "Ö", "Oe", "Ü", "Ue", "ä", "ae", "ö", "oe", "ü", "ue", "ß", "ss")
commonName = viper.GetString("cn")
......@@ -92,7 +93,6 @@ var requestCmd *cobra.Command = &cobra.Command{
basefilename = sanitize.Name(commonName)
// generate output directory name
spew.Dump(viper.GetString("outdir"))
if !viper.IsSet("outdir") {
outputdir = basefilename + "_" + cmdArguments.TimeStamp
viper.Set("outdir", outputdir)
......@@ -102,8 +102,8 @@ var requestCmd *cobra.Command = &cobra.Command{
// last chance fallback…
outputdir = viper.GetString("outdir")
}
outdirwriter := strings.Builder{}
directoryTemplate.Execute(&outdirwriter, cmdArguments)
outdirwriter := bytes.Buffer{}
err = directoryTemplate.Execute(&outdirwriter, cmdArguments)
if err != nil {
// last chance fallback…
outputdir = viper.GetString("outdir")
......@@ -111,18 +111,20 @@ var requestCmd *cobra.Command = &cobra.Command{
outputdir = outdirwriter.String()
}
// create output path
err = os.MkdirAll(outputdir, 0700)
if err != nil {
log.Fatalf("Unable to create output directory %s: %s", outputdir, err)
} else {
log.Printf("Output directory is »%s«", outputdir)
if viper.GetBool("dry-run") == false {
err = os.MkdirAll(outputdir, 0700)
if err != nil {
log.Fatalf("Unable to create output directory %s: %s", outputdir, err)
}
}
log.Printf("Output directory is »%s«", outputdir)
// create http client
client, err := dfnpki.GetHTTPClient()
httpclient, err := dfnpki.GetHTTPClient()
if err != nil {
log.Fatal(err)
}
client := dfnpki.NewSoapClient(httpclient, dfnpki.GeneratePublicURL(viper.GetString("ca")))
// generate PIN if needed
if viper.GetString("PIN") == "" {
......@@ -130,12 +132,13 @@ var requestCmd *cobra.Command = &cobra.Command{
log.Printf("Generated PIN: »%s«", viper.GetString("PIN"))
}
filename := filepath.Join(outputdir, basefilename+".PIN.txt")
err = ioutil.WriteFile(filename, []byte(viper.GetString("PIN")), 0644)
if err != nil {
log.Fatalf("Unable to write PIN file %s: %s", filename, err)
} else {
log.Printf("Wrote PIN to »%s«", filename)
if viper.GetBool("dry-run") == false {
err = ioutil.WriteFile(filename, []byte(viper.GetString("PIN")), 0644)
if err != nil {
log.Fatalf("Unable to write PIN file %s: %s", filename, err)
}
}
log.Printf("Wrote PIN to »%s«", filename)
// handle private key
keyfilename := viper.GetString("keyfile")
......@@ -143,42 +146,46 @@ var requestCmd *cobra.Command = &cobra.Command{
// read keyfile
keybytes, err := ioutil.ReadFile(keyfilename)
if err != nil {
log.Fatal("Unable to read secret key from file %s: %s", keyfilename, err)
log.Fatalf("Unable to read secret key from file %s: %s", keyfilename, err)
}
pkey, err = dfnpki.ParsePrivateKey(keybytes, []byte(viper.GetString("keypass")))
if err != nil {
log.Fatal("Unable to parse secret key from file %s: %s", keyfilename, err)
log.Fatalf("Unable to parse secret key from file %s: %s", keyfilename, err)
}
log.Printf("Read private key with %d bytes from %s", pkey.N.BitLen(), keyfilename)
} else {
// generate key
pkey, err = dfnpki.NewPrivateKey(viper.GetInt("keysize"))
if err != nil {
log.Fatal("Unable to generate secret key: %s", err)
log.Fatalf("Unable to generate secret key: %s", err)
} else {
log.Printf("Private rsa key with %d bytes generated", pkey.N.BitLen())
}
// save key as pkcs1/der
pkcs1key := x509.MarshalPKCS1PrivateKey(pkey)
filename := filepath.Join(outputdir, basefilename+".key.der")
err = ioutil.WriteFile(filename, pkcs1key, 0600)
if err != nil {
log.Fatalf("Unable to write private to »%s« as PKCS1/DER: %s", filename, err)
} else {
log.Printf("Wrote private key to »%s« (format: PKCS1/DER)", filename)
if viper.GetBool("dry-run") == false {
err = ioutil.WriteFile(filename, pkcs1key, 0600)
if err != nil {
log.Fatalf("Unable to write private to »%s« as PKCS1/DER: %s", filename, err)
}
}
log.Printf("Wrote private key to »%s« (format: PKCS1/DER)", filename)
// save key as pkcs1/pem
pemkey := pem.EncodeToMemory(&pem.Block{
Bytes: pkcs1key,
Type: "RSA PRIVATE KEY",
})
filename = filepath.Join(outputdir, basefilename+".key.pem")
err = ioutil.WriteFile(filename, pemkey, 0600)
if err != nil {
log.Fatalf("Unable to write private to »%s« as PKCS1/PEM: %s", filename, err)
} else {
log.Printf("Wrote private key to »%s« (format: PKCS1/PEM)", filename)
if viper.GetBool("dry-run") == false {
err = ioutil.WriteFile(filename, pemkey, 0600)
if err != nil {
log.Fatalf("Unable to write private to »%s« as PKCS1/PEM: %s", filename, err)
}
}
log.Printf("Wrote private key to »%s« (format: PKCS1/PEM)", filename)
}
// prepare certificate request
......@@ -239,12 +246,13 @@ var requestCmd *cobra.Command = &cobra.Command{
log.Fatal("Unable to generate pkcs10 certificate request: ", err)
}
filename = filepath.Join(outputdir, basefilename+".req")
err = ioutil.WriteFile(filename, []byte(csr), 0644)
if err != nil {
log.Fatalf("Unable to write request file %s: %s", filename, err)
} else {
log.Printf("Wrote request to »%s« (format: PKCS10)", filename)
if viper.GetBool("dry-run") == false {
err = ioutil.WriteFile(filename, []byte(csr), 0644)
if err != nil {
log.Fatalf("Unable to write request file %s: %s", filename, err)
}
}
log.Printf("Wrote request to »%s« (format: PKCS10)", filename)
// generate compatible argument for SAN addition via API
var SubjectAlternativeNames []string
......@@ -290,7 +298,7 @@ var requestCmd *cobra.Command = &cobra.Command{
Pkcs10: csr,
AltNames: SubjectAlternativeNames,
Role: dfnrole,
PIN: viper.GetString("PIN"),
PIN: viper.GetString("pin"),
AddName: viper.GetString("RequesterName"),
AddEMail: viper.GetString("RequesterEmail"),
AddOrgUnit: viper.GetString("RequesterOU"),
......@@ -298,37 +306,41 @@ var requestCmd *cobra.Command = &cobra.Command{
}
// make request
//spew.Dump(requestData, SubjectAlternativeNames, commonName)
publicAPIEndpoint := dfnpki.GeneratePublicURL(viper.GetString("ca"))
//fmt.Println(publicAPIEndpoint)
requestID, err := dfnpki.NewRequest(client, publicAPIEndpoint, csr, requestData)
if err != nil {
log.Fatal("Error sending request to api endpoint: ", err)
var requestID string
if viper.GetBool("dry-run") == false {
requestID, err = dfnpki.NewRequest(client, csr, requestData)
if err != nil {
log.Fatal("Error sending request to api endpoint: ", err)
}
} else {
requestID = "DRYRUN"
}
log.Printf("New request with ID %s created", requestID)
// save request id
filename = filepath.Join(outputdir, basefilename+".request-id.txt")
err = ioutil.WriteFile(filename, []byte(requestID+"\n"), 0644)
if err != nil {
log.Fatalf("Unable to write request file %s: %s", filename, err)
} else {
log.Printf("Request ID written to »%s«", filename)
if viper.GetBool("dry-run") == false {
err = ioutil.WriteFile(filename, []byte(requestID+"\n"), 0644)
if err != nil {
log.Fatalf("Unable to write request file %s: %s", filename, err)
}
}
log.Printf("Request ID written to »%s«", filename)
// fetch PDF
if viper.GetBool("SkipPDF") == false {
pdf, err := dfnpki.GetRequestPrintout(client, viper.GetInt("ra-id"), requestID, viper.GetString("PIN"))
pdf, err := dfnpki.GetRequestPrintout(client, viper.GetInt("ra-id"), requestID, viper.GetString("pin"))
if err != nil {
log.Fatalf("Unable to retrieve PDF: %s", err)
}
filename = filepath.Join(outputdir, basefilename+".request.pdf")
ioutil.WriteFile(filename, pdf, 0644)
if err != nil {
log.Fatalf("Unable to write PDF file »%s«: %s", filename, err)
} else {
log.Printf("PDF request saved to »%s«", filename)
if viper.GetBool("dry-run") == false {
ioutil.WriteFile(filename, pdf, 0644)
if err != nil {
log.Fatalf("Unable to write PDF file »%s«: %s", filename, err)
}
}
log.Printf("PDF request saved to »%s«", filename)
}
},
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment