aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGibheer <gibheer@gmail.com>2015-03-05 21:37:52 +0100
committerGibheer <gibheer@gmail.com>2015-03-05 21:37:52 +0100
commit52102b0f24b03be251efa863c3b7cd657f09d5d9 (patch)
tree4c1ba442c8f824c9cbfb5444a02940fd865cdd72
parent2954be520de58f9760d378fb87be92b448666401 (diff)
finally add certificate sign request generation
This adds finally a way to create certificate sign requests. There are still some options missing, but it is coming together. With the next step, the ccertificate data container will probably be put into the pki library.
-rw-r--r--certificate_data.go28
-rw-r--r--flags.go115
-rw-r--r--main.go21
3 files changed, 151 insertions, 13 deletions
diff --git a/certificate_data.go b/certificate_data.go
new file mode 100644
index 0000000..76f3323
--- /dev/null
+++ b/certificate_data.go
@@ -0,0 +1,28 @@
+package main
+
+import (
+ "crypto/x509"
+ "crypto/x509/pkix"
+ "net"
+)
+
+type (
+ certificateData struct {
+ Subject pkix.Name
+
+ DnsNames []string
+ EmailAddresses []string
+ IpAddresses []net.IP
+ }
+)
+
+func (c *certificateData) GenerateCSR() *x509.CertificateRequest {
+ csr := &x509.CertificateRequest{}
+
+ csr.Subject = c.Subject
+ csr.DNSNames = c.DnsNames
+ csr.IPAddresses = c.IpAddresses
+ csr.EmailAddresses = c.EmailAddresses
+
+ return csr
+}
diff --git a/flags.go b/flags.go
index f67657e..7aee688 100644
--- a/flags.go
+++ b/flags.go
@@ -5,11 +5,15 @@ package main
import (
"crypto/elliptic"
+ "crypto/x509/pkix"
"encoding/base64"
"flag"
"fmt"
"io"
+ "net"
"os"
+ "reflect"
+ "strings"
"github.com/gibheer/pki"
)
@@ -26,17 +30,22 @@ var (
type (
// holds all certificate related flags, which need parsing afterwards
certFlagsContainer struct {
- serialNumber int // 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)
- 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
+ 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
@@ -64,9 +73,10 @@ type (
Output io.WriteCloser
// signature from the args
Signature []byte
-
// private key specific stuff
PrivateKeyGenerationFlags privateKeyGenerationFlags
+ // a certificate filled with the parameters
+ CertificateData certificateData
}
privateKeyGenerationFlags struct {
@@ -253,3 +263,84 @@ func (f *Flags) parseSignature() error {
if err != nil { return err }
return nil
}
+
+// add the certificate fields to the flags
+func (f *Flags) AddCertificateFields() {
+ f.check_list = append(f.check_list, f.parseCertificateFields)
+ f.flagset.StringVar(
+ &f.flag_container.certificateFlags.manual.serialNumber,
+ "serial", "1", "unique serial number of the CA");
+ f.flagset.StringVar(
+ &f.flag_container.certificateFlags.manual.commonName,
+ "common-name", "", "common name of the entity to certify");
+ f.flagset.StringVar(
+ &f.flag_container.certificateFlags.manual.dnsNames,
+ "dns-names", "", "comma separated list of alternative fqdn entries for the entity");
+ f.flagset.StringVar(
+ &f.flag_container.certificateFlags.manual.emailAddresses,
+ "email-address", "", "comma separated list of alternative email entries for the entity");
+ f.flagset.StringVar(
+ &f.flag_container.certificateFlags.manual.ipAddresses,
+ "ip-address", "", "comma separated list of alternative ip entries for the entity");
+ f.flagset.StringVar(
+ &f.flag_container.certificateFlags.automatic.Country,
+ "country", "", "comma separated list of countries the entitiy resides in");
+ f.flagset.StringVar(
+ &f.flag_container.certificateFlags.automatic.Organization,
+ "organization", "", "comma separated list of organizations the entity belongs to");
+ f.flagset.StringVar(
+ &f.flag_container.certificateFlags.automatic.OrganizationalUnit,
+ "organization-unit", "", "comma separated list of organization units or departments the entity belongs to");
+ f.flagset.StringVar(
+ &f.flag_container.certificateFlags.automatic.Locality,
+ "locality", "", "comma separated list of localities or cities the entity resides in");
+ f.flagset.StringVar(
+ &f.flag_container.certificateFlags.automatic.Province,
+ "province", "", "comma separated list of provinces the entity resides in");
+ f.flagset.StringVar(
+ &f.flag_container.certificateFlags.automatic.StreetAddress,
+ "street-address", "", "comma separated list of street addresses the entity resides in");
+ f.flagset.StringVar(
+ &f.flag_container.certificateFlags.automatic.PostalCode,
+ "postal-code", "", "comma separated list of postal codes of the localities");
+}
+
+// parse the certificate fields into a raw certificate
+func (f *Flags) parseCertificateFields() error {
+ f.Flags.CertificateData = certificateData{Subject: pkix.Name{}}
+ // convert the automatic flags
+ container_type := reflect.ValueOf(&f.flag_container.certificateFlags.automatic).Elem()
+ cert_data_type := reflect.ValueOf(&f.Flags.CertificateData.Subject).Elem()
+
+ for _, field := range []string{"Country", "Organization", "OrganizationalUnit",
+ "Locality", "Province", "StreetAddress", "PostalCode"} {
+ field_value := container_type.FieldByName(field).String()
+ if field_value == "" { continue }
+ target := cert_data_type.FieldByName(field)
+ target.Set(reflect.ValueOf(strings.Split(field_value, ",")))
+ }
+
+ // convert the manual flags
+ data := &f.Flags.CertificateData
+ raw_data := f.flag_container.certificateFlags.manual
+ data.Subject.SerialNumber = raw_data.serialNumber
+ data.Subject.CommonName = raw_data.commonName
+ if raw_data.dnsNames != "" {
+ data.DnsNames = strings.Split(raw_data.dnsNames, ",")
+ }
+ if raw_data.emailAddresses != "" {
+ data.EmailAddresses = strings.Split(raw_data.emailAddresses, ",")
+ }
+
+ if raw_data.ipAddresses == "" { return nil }
+ raw_ips := strings.Split(raw_data.ipAddresses, ",")
+ data.IpAddresses = make([]net.IP, len(raw_ips))
+ for i, ip := range raw_ips {
+ data.IpAddresses[i] = net.ParseIP(ip)
+ if data.IpAddresses[i] == nil {
+ return fmt.Errorf("'%s' is not a valid IP", ip)
+ }
+ }
+
+ return nil
+}
diff --git a/main.go b/main.go
index c509fd7..b33ced9 100644
--- a/main.go
+++ b/main.go
@@ -2,7 +2,10 @@ package main
import (
"crypto"
+ "crypto/rand"
+ "crypto/x509"
"encoding/base64"
+ "encoding/pem"
"fmt"
"io"
"io/ioutil"
@@ -25,7 +28,7 @@ func main() {
case "create-public": create_public_key()
case "sign-input": sign_input()
case "verify-signature": verify_input()
-// case "create-cert-sign": create_sign_request()
+ case "create-cert-sign": create_sign_request()
// case "sign-request": sign_request()
case "help": print_modules()
// case "info": info_on_file()
@@ -115,6 +118,22 @@ func verify_input() {
os.Exit(1)
}
+// create a certificate sign request
+func create_sign_request() {
+ fs := NewFlags("create-cert-sign")
+ fs.AddPrivateKey()
+ fs.AddOutput()
+ fs.AddCertificateFields()
+ fs.Parse(program_args())
+
+ csrt := fs.Flags.CertificateData.GenerateCSR()
+ csr, err := x509.CreateCertificateRequest(rand.Reader, csrt, fs.Flags.PrivateKey.PrivateKey())
+ if err != nil { crash_with_help(2, "Could not create certificate sign request: %s", err) }
+ pem_block := &pem.Block{Type: "CERTIFICATE REQUEST", Bytes: csr}
+ err = pem.Encode(fs.Flags.Output, pem_block)
+ if err != nil { crash_with_help(2, "Encoding didn't work: %s", err) }
+}
+
// print the module help
func print_modules() {
fmt.Printf(`Usage: %s command args