diff --git a/ca.go b/ca.go index 195c265..6f29ce0 100644 --- a/ca.go +++ b/ca.go @@ -27,6 +27,8 @@ type CA struct { Country string `hcl:"country"` Organization string `hcl:"organization"` SerialType string `hcl:"serial_type"` + KeySize int `hcl:"key_size,optional"` + Validity string `hcl:"validity,optional"` Paths Paths `hcl:"paths,block"` } @@ -54,8 +56,39 @@ func LoadCA(path string) (*CA, error) { return &config.CA, nil } +func parseValidity(validity string) (time.Duration, error) { + if validity == "" { + return time.Hour * 24 * 365 * 5, nil // default 5 years + } + var n int + var unit rune + _, err := fmt.Sscanf(validity, "%d%c", &n, &unit) + if err != nil { + // If no unit, assume years + _, err2 := fmt.Sscanf(validity, "%d", &n) + if err2 != nil { + return 0, fmt.Errorf("invalid validity format: %s", validity) + } + unit = 'y' + } + switch unit { + case 'y': + return time.Hour * 24 * 365 * time.Duration(n), nil + case 'm': + return time.Hour * 24 * 30 * time.Duration(n), nil + case 'd': + return time.Hour * 24 * time.Duration(n), nil + default: + return 0, fmt.Errorf("invalid validity unit: %c", unit) + } +} + func GenerateCA(ca *CA) ([]byte, []byte, error) { - priv, err := rsa.GenerateKey(rand.Reader, 4096) + keySize := ca.KeySize + if keySize == 0 { + keySize = 4096 + } + priv, err := rsa.GenerateKey(rand.Reader, keySize) if err != nil { return nil, nil, err } @@ -64,6 +97,11 @@ func GenerateCA(ca *CA) ([]byte, []byte, error) { if err != nil { return nil, nil, fmt.Errorf("failed to generate serial number: %v", err) } + validity, err := parseValidity(ca.Validity) + if err != nil { + return nil, nil, err + } + now := time.Now() tmpl := x509.Certificate{ SerialNumber: serialNumber, Subject: pkix.Name{ @@ -71,8 +109,8 @@ func GenerateCA(ca *CA) ([]byte, []byte, error) { Organization: []string{ca.Organization}, CommonName: ca.Name, }, - NotBefore: time.Now(), - NotAfter: time.Now().AddDate(10, 0, 0), + NotBefore: now, + NotAfter: now.Add(validity), KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign, BasicConstraintsValid: true, IsCA: true,