aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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