@@ -40,19 +40,40 @@ type Pair struct {
4040 Key []byte
4141}
4242
43+ type configs struct {
44+ cnPrefix string
45+ dnsNames []string
46+ }
47+
48+ type Option func (opt * configs )
49+
50+ // WithCNPrefix adds cnPrefix as prefix for the CN.
51+ func WithCNPrefix (cnPrefix string ) Option {
52+ return func (opt * configs ) {
53+ opt .cnPrefix = cnPrefix
54+ }
55+ }
56+
57+ // WithDNSNames adds dnsNames to the DNSNames.
58+ func WithDNSNames (dnsNames ... string ) Option {
59+ return func (opt * configs ) {
60+ opt .dnsNames = dnsNames
61+ }
62+ }
63+
4364// NewRootCA generates a new x509 Certificate using ECDSA P-384 and returns:
4465// - the private key
4566// - the certificate
4667// - the certificate and its key in PEM format as a byte slice.
4768//
4869// If any error occurs during the generation process, a non-nil error is returned.
49- func NewRootCA () (crypto.PrivateKey , * x509.Certificate , Pair , error ) {
70+ func NewRootCA (opts ... Option ) (crypto.PrivateKey , * x509.Certificate , Pair , error ) {
5071 rootKey , err := ecdsa .GenerateKey (elliptic .P384 (), rand .Reader )
5172 if err != nil {
5273 return nil , nil , Pair {}, fmt .Errorf ("could not create private key: %w" , err )
5374 }
5475
55- cert , pair , err := newRootCert (rootKey , & rootKey .PublicKey )
76+ cert , pair , err := newRootCert (rootKey , & rootKey .PublicKey , opts ... )
5677 return rootKey , cert , pair , err
5778}
5879
@@ -62,12 +83,12 @@ func NewRootCA() (crypto.PrivateKey, *x509.Certificate, Pair, error) {
6283// - the certificate and its key in PEM format as a byte slice.
6384//
6485// If any error occurs during the generation process, a non-nil error is returned.
65- func NewRSARootCA () (crypto.PrivateKey , * x509.Certificate , Pair , error ) {
86+ func NewRSARootCA (opts ... Option ) (crypto.PrivateKey , * x509.Certificate , Pair , error ) {
6687 rootKey , err := rsa .GenerateKey (rand .Reader , 2048 )
6788 if err != nil {
6889 return nil , nil , Pair {}, fmt .Errorf ("could not create private key: %w" , err )
6990 }
70- cert , pair , err := newRootCert (rootKey , & rootKey .PublicKey )
91+ cert , pair , err := newRootCert (rootKey , & rootKey .PublicKey , opts ... )
7192 return rootKey , cert , pair , err
7293}
7394
@@ -77,7 +98,36 @@ func NewRSARootCA() (crypto.PrivateKey, *x509.Certificate, Pair, error) {
7798// - a Pair with the certificate and its key im PEM format
7899//
79100// If any error occurs during the generation process, a non-nil error is returned.
80- func GenerateChildCert (name string , ips []net.IP , caPrivKey crypto.PrivateKey , caCert * x509.Certificate ) (* tls.Certificate , Pair , error ) {
101+ func GenerateChildCert (name string , ips []net.IP , caPrivKey crypto.PrivateKey , caCert * x509.Certificate , opts ... Option ) (* tls.Certificate , Pair , error ) {
102+ priv , err := ecdsa .GenerateKey (elliptic .P384 (), rand .Reader )
103+ if err != nil {
104+ return nil , Pair {}, fmt .Errorf ("could not create ECDSA private key: %w" , err )
105+ }
106+
107+ cert , childPair , err :=
108+ GenerateGenericChildCert (
109+ name ,
110+ ips ,
111+ priv ,
112+ & priv .PublicKey ,
113+ caPrivKey ,
114+ caCert ,
115+ opts ... )
116+ if err != nil {
117+ return nil , Pair {}, fmt .Errorf (
118+ "could not generate child TLS certificate CA: %w" , err )
119+ }
120+
121+ return cert , childPair , nil
122+ }
123+
124+ // GenerateRSAChildCert generates a RSA with a 2048-bit key x509 Certificate as a
125+ // child of caCert and returns the following:
126+ // - the certificate and private key as a tls.Certificate
127+ // - a Pair with the certificate and its key im PEM format
128+ //
129+ // If any error occurs during the generation process, a non-nil error is returned.
130+ func GenerateRSAChildCert (name string , ips []net.IP , caPrivKey crypto.PrivateKey , caCert * x509.Certificate , opts ... Option ) (* tls.Certificate , Pair , error ) {
81131 priv , err := rsa .GenerateKey (rand .Reader , 2048 )
82132 if err != nil {
83133 return nil , Pair {}, fmt .Errorf ("could not create RSA private key: %w" , err )
@@ -90,10 +140,11 @@ func GenerateChildCert(name string, ips []net.IP, caPrivKey crypto.PrivateKey, c
90140 priv ,
91141 & priv .PublicKey ,
92142 caPrivKey ,
93- caCert )
143+ caCert ,
144+ opts ... )
94145 if err != nil {
95146 return nil , Pair {}, fmt .Errorf (
96- "could not generate child TLS certificate CA : %w" , err )
147+ "could not generate child TLS certificate: %w" , err )
97148 }
98149
99150 return cert , childPair , nil
@@ -115,18 +166,26 @@ func GenerateGenericChildCert(
115166 priv crypto.PrivateKey ,
116167 pub crypto.PublicKey ,
117168 caPrivKey crypto.PrivateKey ,
118- caCert * x509.Certificate ) (* tls.Certificate , Pair , error ) {
169+ caCert * x509.Certificate ,
170+ opts ... Option ) (* tls.Certificate , Pair , error ) {
119171
172+ cfg := getCgf (opts )
173+
174+ cn := "Police Public Call Box"
175+ if cfg .cnPrefix != "" {
176+ cn = fmt .Sprintf ("[%s] %s" , cfg .cnPrefix , cn )
177+ }
178+ dnsNames := append ([]string {name }, cfg .dnsNames ... )
120179 notBefore , notAfter := makeNotBeforeAndAfter ()
121180
122181 certTemplate := & x509.Certificate {
123- DNSNames : [] string { name } ,
182+ DNSNames : dnsNames ,
124183 IPAddresses : ips ,
125184 SerialNumber : big .NewInt (1658 ),
126185 Subject : pkix.Name {
127186 Locality : []string {"anywhere in time and space" },
128187 Organization : []string {"TARDIS" },
129- CommonName : "Police Public Call Box" ,
188+ CommonName : cn ,
130189 },
131190 NotBefore : notBefore ,
132191 NotAfter : notAfter ,
@@ -220,7 +279,12 @@ func NewRSARootAndChildCerts() (Pair, Pair, error) {
220279// - a Pair containing the certificate and private key in PEM format.
221280//
222281// If an error occurs during certificate creation, it returns a non-nil error.
223- func newRootCert (priv crypto.PrivateKey , pub crypto.PublicKey ) (* x509.Certificate , Pair , error ) {
282+ func newRootCert (priv crypto.PrivateKey , pub crypto.PublicKey , opts ... Option ) (* x509.Certificate , Pair , error ) {
283+ cn := "High Council"
284+ cfg := getCgf (opts )
285+ if cfg .cnPrefix != "" {
286+ cn = fmt .Sprintf ("[%s] %s" , cfg .cnPrefix , cn )
287+ }
224288 notBefore , notAfter := makeNotBeforeAndAfter ()
225289
226290 rootTemplate := x509.Certificate {
@@ -230,7 +294,7 @@ func newRootCert(priv crypto.PrivateKey, pub crypto.PublicKey) (*x509.Certificat
230294 Locality : []string {"The Capitol" },
231295 OrganizationalUnit : []string {"Time Lords" },
232296 Organization : []string {"High Council of the Time Lords" },
233- CommonName : "High Council" ,
297+ CommonName : cn ,
234298 },
235299 NotBefore : notBefore ,
236300 NotAfter : notAfter ,
@@ -286,6 +350,14 @@ func newRootCert(priv crypto.PrivateKey, pub crypto.PublicKey) (*x509.Certificat
286350 }, nil
287351}
288352
353+ func getCgf (opts []Option ) configs {
354+ cfg := configs {dnsNames : []string {}}
355+ for _ , opt := range opts {
356+ opt (& cfg )
357+ }
358+ return cfg
359+ }
360+
289361// defaultChildCert generates a child certificate for localhost and 127.0.0.1.
290362// It returns the certificate and its key as a Pair and an error if any happens.
291363func defaultChildCert (
0 commit comments