diff --git a/certificate.go b/certificate.go index acb4b5a..0973793 100644 --- a/certificate.go +++ b/certificate.go @@ -47,7 +47,7 @@ var ( 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", + Example: "create-cert -private-key=foo.ecdsa -csr=foo.csr", Run: create_cert, } // certificate specific creation stuff @@ -92,7 +92,7 @@ type ( // 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().BoolVar(&flagContainer.certGeneration.isCA, "is-ca", false, "check if the resulting certificate should be a ca") cmd.Flags().IntVar( &flagContainer.certGeneration. length, @@ -131,17 +131,29 @@ func InitFlagCert(cmd *Command) { // create a certificate func create_cert(cmd *Command, args []string) { - err := checkFlags(checkPrivateKey, checkOutput, checkCSR, checkCertFlags) + err := checkFlags(checkPrivateKey, checkOutput, checkCSR, checkCertFlags, checkFlagsEither(checkIsCA, checkCA)) if err != nil { crash_with_help(cmd, ErrorFlagInput, "Flags invalid: %s", err) } + var cert *pki.Certificate + if FlagCertificateGeneration.IsCA && FlagCertificate == nil { + cert, err = FlagCertificateSignRequest.ToCertificate( + FlagPrivateKey, + FlagCertificateGeneration, + nil, + ) + } else if !FlagCertificateGeneration.IsCA && FlagCertificate != nil { + cert, err = FlagCertificateSignRequest.ToCertificate( + FlagPrivateKey, + FlagCertificateGeneration, + FlagCertificate, + ) + } else { + crash_with_help(cmd, ErrorFlagInput, "Usage of 'is-ca' and 'ca' is invalid.") + } + // 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) } @@ -187,6 +199,14 @@ func checkCertFlags() error { return nil } +// check if the flag is enabled to make the certificate a ca +func checkIsCA() error { + if FlagCertificateGeneration.IsCA { + return nil + } + return fmt.Errorf("Not selected to be a CA") +} + // parse the key usage string func convertCertKeyUsage() error { if keyUstr := flagContainer.certGeneration.keyUsage; keyUstr != "" { @@ -229,9 +249,42 @@ func convertCertCrlUrl() error { return nil } +// add flag to load a certificate +func InitFlagCA(cmd *Command) { + cmd.Flags().StringVar(&flagContainer.caPath, "ca", "", "path to the certificate authority") +} + +// parse the certificate authority +func checkCA() error { + rest, err := ioutil.ReadFile(flagContainer.caPath) + if err != nil { + return fmt.Errorf("Error reading certificate authority: %s", err) + } + + var ca_asn1 []byte + var block *pem.Block + for len(rest) > 0 { + block, rest = pem.Decode(rest) + if block != nil && block.Type == pki.PemLabelCertificate { + ca_asn1 = block.Bytes + break + } + } + if len(ca_asn1) == 0 { + return fmt.Errorf("No certificate in '%s' found.", flagContainer.caPath) + } + + ca, err := pki.LoadCertificate(ca_asn1) + if err != nil { + return fmt.Errorf("Invalid certificate: %s", err) + } + FlagCertificate = ca + 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") + cmd.Flags().StringVar(&flagContainer.signRequestPath, "csr", "", "path to the certificate sign request") } // parse the certificate sign request @@ -245,7 +298,7 @@ func checkCSR() error { var block *pem.Block for len(rest) > 0 { block, rest = pem.Decode(rest) - if block.Type == "CERTIFICATE REQUEST" { + if block.Type == pki.PemLabelCertificateRequest { csr_asn1 = block.Bytes break } diff --git a/flags.go b/flags.go index cb69398..29c2941 100644 --- a/flags.go +++ b/flags.go @@ -28,7 +28,7 @@ type ( certificateFlags certiticateRequestRawFlags // container for certificate related flags signature string // a base64 encoded signature certGeneration certGenerationRaw // all certificate generation flags - certificatePath string // path to a certificate + caPath string // path to a certificate authority } flagCheck func() error @@ -90,6 +90,8 @@ certificate requests and certificates and sign/verify messages.`, FlagCertificateRequestData *pki.CertificateData // the certificate sign request FlagCertificateSignRequest *pki.CertificateRequest + // the ca/certificate to use + FlagCertificate *pki.Certificate ) func InitFlags() { @@ -123,12 +125,14 @@ func InitFlags() { InitFlagOutput(CmdCreateSignRequest) InitFlagCertificateFields(CmdCreateSignRequest) // create-certificate - InitFlagPrivateKey(CmdCreateCert) - InitFlagOutput(CmdCreateCert) + InitFlagCA(CmdCreateCert) InitFlagCert(CmdCreateCert) InitFlagCSR(CmdCreateCert) + InitFlagOutput(CmdCreateCert) + InitFlagPrivateKey(CmdCreateCert) } +// check if all checks are successful func checkFlags(checks ...flagCheck) error { for _, check := range checks { if err := check(); err != nil { @@ -138,6 +142,23 @@ func checkFlags(checks ...flagCheck) error { return nil } +// check if either of the inserted checks is successful +func checkFlagsEither(checks ...flagCheck) flagCheck { + return func() error { + errors := make([]error, 0) + for _, check := range checks { + if err := check(); err != nil { + errors = append(errors, err) + } + } + // it is a success, if any check is successful + if len(checks)-len(errors) > 0 { + return nil + } + return errors[0] + } +} + // add the public key flag func InitFlagPublicKey(cmd *Command) { cmd.Flags().StringVar(&flagContainer.publicKeyPath, "public-key", "", "path to the public key (required)")