File Coverage

blib/lib/App/sslmaker.pm
Criterion Covered Total %
statement 172 180 95.5
branch 63 86 73.2
condition 23 40 57.5
subroutine 34 34 100.0
pod 12 12 100.0
total 304 352 86.3


line stmt bran cond sub pod time code
1             package App::sslmaker;
2 6     6   635623 use strict;
  6         12  
  6         211  
3 6     6   43 use warnings;
  6         14  
  6         365  
4              
5 6     6   32 use Carp qw(confess croak);
  6         8  
  6         348  
6 6     6   3766 use Data::Dumper ();
  6         49832  
  6         196  
7 6     6   4593 use Path::Tiny;
  6         81771  
  6         510  
8 6     6   2974 use File::umask;
  6         52573  
  6         833  
9              
10 6   50 6   43 use constant DEBUG => $ENV{SSLMAKER_DEBUG} || 0;
  6         8  
  6         546  
11 6   50 6   39 use constant DEFAULT_BITS => $ENV{SSLMAKER_BITS} || 4096;
  6         18  
  6         343  
12 6   50 6   30 use constant DEFAULT_DAYS => $ENV{SSLMAKER_DAYS} || 365;
  6         8  
  6         1901  
13              
14             our $VERSION = '0.21';
15             our $OPENSSL = $ENV{SSLMAKER_OPENSSL} || 'openssl';
16              
17             my @CONFIG_TEMPLATE_KEYS = qw(bits cert crl_days days home key);
18              
19             # heavily inspired by Mojo::Loader::_all()
20             my %DATA = do {
21             seek DATA, 0, 0;
22             my $data = join '', ;
23             $data =~ s/^.*\n__DATA__\r?\n/\n/s;
24             $data =~ s/\n__END__\r?\n.*$/\n/s;
25             $data = [split /^@@\s*(.+?)\s*\r?\n/m, $data];
26             shift @$data; # first element is empty string
27             @$data;
28             };
29              
30             # need to be defined up front
31             sub openssl {
32 35 100   35 1 3022 my $cb = ref $_[-1] eq 'CODE' ? pop : sub { print STDERR $_[1] if DEBUG == 2 and length $_[1] };
  42     42   7902  
33 42 100       221 my $self = ref $_[0] ? shift : __PACKAGE__;
34 42         90 my $buf = '';
35              
36 6     6   3130 use IPC::Open3;
  6         29025  
  6         366  
37 6     6   37 use Symbol;
  6         10  
  6         19256  
38 42         68 $self->_d("\$ $OPENSSL @_") if DEBUG;
39 42         353 my $OUT = gensym;
40 42         1935 my $pid = open3(undef, $OUT, $OUT, $OPENSSL => @_);
41              
42 42         408986 while (1) {
43 386         236714655 my $l = sysread $OUT, my $read, 8096;
44 386 50       1748 croak "$OPENSSL: $!" unless defined $l;
45 386 100       1168 last unless $l;
46 344         984 $buf .= $read;
47             }
48              
49 42         2395 waitpid $pid, 0;
50 42 100       1184 return $self->$cb($buf) unless $?;
51 1         538 croak $buf;
52             }
53              
54             sub make_cert {
55 4     4 1 41 my ($self, $args) = @_;
56 4 50       61 my $asset = $args->{cert} ? Path::Tiny->new($args->{cert}) : Path::Tiny->tempfile;
57              
58 4         72 local $UMASK = 0222; # make files with mode 444
59 4 50       107 croak 'Parameter "subject" is required' unless my $subject = $self->_render_subject($self->subject, $args->{subject});
60 0 50       0 openssl qw(req -new -sha256 -x509 -extensions v3_ca), (map { (-addext => $_) } grep {length} @{$args->{ext} || []}),
  0         0  
  4         63  
61             -passin => $self->_passphrase($args->{passphrase}),
62             -days => $args->{days} || DEFAULT_DAYS,
63             -key => $args->{key},
64 4   100     20 -out => $asset->path,
65             -subj => $subject;
66              
67 4         312 return $asset;
68             }
69              
70             sub make_crl {
71 2     2 1 136 my ($self, $args) = @_;
72 2 50       149 my $asset = $args->{crl} ? Path::Tiny->new($args->{crl}) : Path::Tiny->tempfile;
73              
74 2         165 local $UMASK = 0122; # make files with mode 644
75              
76             openssl qw(ca -gencrl),
77             -keyfile => $args->{key},
78             -cert => $args->{cert},
79 2 50       188 $args->{passphrase} ? (-passin => $self->_passphrase($args->{passphrase})) : (), -out => $asset->path;
80              
81 2         93 return $asset;
82             }
83              
84             sub make_csr {
85 8     8 1 2044 my ($self, $args) = @_;
86 8 100       338 my $asset = $args->{csr} ? Path::Tiny->new($args->{csr}) : Path::Tiny->tempfile;
87              
88 8         2011 local $UMASK = 0277; # make files with mode 400
89              
90 8 50       206 croak 'Parameter "subject" is required' unless my $subject = $self->_render_subject($self->subject, $args->{subject});
91             openssl qw(req -new -sha256), $args->{passphrase} ? (-passin => $self->_passphrase($args->{passphrase})) : (),
92 2 100       56 (map { (-addext => $_) } grep {length} @{$args->{ext} || []}),
  2         28  
  8         265  
93             -key => $args->{key},
94 8 100       85 -out => $asset->path,
95             -subj => $subject;
96              
97 8         440 return $asset;
98             }
99              
100             sub make_directories {
101 7     7 1 3840 my ($self, $args) = @_;
102 7         67 my $home = $self->_home($args);
103 7         598 my $file;
104              
105 7         72 $home->mkpath;
106 7 50       3742 -w $home or croak "Can't write to $home";
107 7         280 mkdir $home->child($_) for qw(certs csr crl newcerts private);
108 7 50       6442 chmod 0700, $home->child('private') or croak "Couldn't chmod 0700 'private' in $home";
109              
110 7 50       697 if ($args->{templates}) {
111 7         92 local $UMASK = 0122; # make files with mode 644
112 7 50       163 $self->render_to_file('crlnumber', $file, {}) unless -e ($file = $home->child('crlnumber'));
113 7 50       42 $self->render_to_file('index.txt', $file, {}) unless -e ($file = $home->child('index.txt'));
114 7 50       44 $self->render_to_file('index.txt.attr', $file, {}) unless -e ($file = $home->child('index.txt.attr'));
115 7 50       49 $self->render_to_file('serial', $file, {}) unless -e ($file = $home->child('serial'));
116             }
117              
118 7         154 return $args->{home}; # TBD, but will be true
119             }
120              
121             sub make_key {
122 12     12 1 61 my ($self, $args) = @_;
123 12 100       184 my $asset = $args->{key} ? Path::Tiny->new($args->{key}) : Path::Tiny->tempfile;
124 12         24712 my $passphrase;
125              
126 12         143 local $UMASK = 0277; # make files with mode 400
127              
128 12 100       274 if ($passphrase = $args->{passphrase}) {
129 7         44 $passphrase = $self->_passphrase($passphrase);
130 7 50 33     586 Path::Tiny->new($1)->spew({binmode => ':raw'}, $self->_random_passphrase(64))
131             if $passphrase =~ m!^file:(.+)! and !-e $1;
132             }
133              
134             openssl 'genrsa', $passphrase ? (-aes256 => -passout => $passphrase) : (),
135             -out => $asset->path,
136 12 100 100     7193 $args->{bits} || DEFAULT_BITS;
137              
138 12         743 return $asset;
139             }
140              
141             # copy/paste from Mojo::Base::new()
142             sub new {
143 17     17 1 1268016 my $class = shift;
144 17 50 33     404 bless @_ ? @_ > 1 ? {@_} : {%{$_[0]}} : {}, ref $class || $class;
  0 100       0  
145             }
146              
147             sub render_to_file {
148 49     49 1 6164 my $stash = pop;
149 49         221 my ($self, $name, $path) = @_;
150 49         259 my $template = $self->_render_template($name, $stash);
151 49         133 my $asset;
152              
153 49 100       536 $asset = $path ? Path::Tiny->new($path) : Path::Tiny->tempfile;
154 49         164701 $asset->spew({binmode => ":raw"}, $template);
155 49         98984 $asset;
156             }
157              
158             sub revoke_cert {
159 2     2 1 25 my ($self, $args) = @_;
160 2         7 my $home = $self->_home($args);
161              
162 2   33     57 local $args->{crl} = $args->{crl} || $home->child('crl.pem');
163              
164             openssl qw(ca), $args->{passphrase} ? (-passin => $self->_passphrase($args->{passphrase})) : (),
165 2 50       118 -revoke => $args->{revoke};
166              
167 2         80 return $self->make_crl($args); # TBD, but will be true
168             }
169              
170             sub sign_csr {
171 7     7 1 39 my ($self, $args) = @_;
172 7 100       116 my $asset = $args->{cert} ? Path::Tiny->new($args->{cert}) : Path::Tiny->tempfile;
173              
174 7         1032 local $UMASK = 0222; # make files with mode 444
175              
176             openssl qw(ca -batch -notext -md sha256),
177             -keyfile => $args->{ca_key},
178             -cert => $args->{ca_cert},
179             -passin => $self->_passphrase($args->{passphrase}),
180             -extensions => $args->{extensions} || 'usr_cert',
181             -out => $asset->path,
182 7   50     205 -in => $args->{csr};
183              
184 7         367 return $asset;
185             }
186              
187             sub subject {
188 20     20 1 1572 my $self = shift;
189 20 100 100     1074 return $self->{subject} // $ENV{SSLMAKER_SUBJECT} // '' unless @_;
      100        
190 6         96 $self->{subject} = $self->_render_subject(@_);
191 6         50 return $self;
192             }
193              
194             sub with_config {
195 28     28 1 36209 my ($self, $cb, $args) = @_;
196 28   100     172 my $key = join ':', 'config', map { ($_, $args->{$_} // ''); } @CONFIG_TEMPLATE_KEYS;
  168         1732  
197              
198 28         486 local $args->{home} = $self->_home($args);
199              
200             {
201 28         3866 local $UMASK = 0177; # read/write for current user
  28         307  
202 28   66     786 $self->{$key} ||= $self->render_to_file('openssl.cnf', $args);
203             }
204              
205 28         316 local $ENV{OPENSSL_CONF} = $self->{$key}->path;
206 28         7177 return $self->$cb($args);
207             }
208              
209             sub _cat {
210 2     2   447 my $self = shift;
211 2         16 my $dest = pop;
212              
213 2 50       74 open my $DEST, '>', $dest or croak "Couldn't write $dest: $!";
214 2         556 local @ARGV = @_;
215 2         46 print $DEST $_ for <>;
216 2 50       618 close $DEST or croak "Couldn't close $dest: $!";
217 2         86 return $dest;
218             }
219              
220             sub _d {
221 35     35   879 return 0 unless DEBUG;
222 0         0 my ($self, $msg) = @_;
223 0         0 print STDERR "$msg\n";
224 0         0 return 0;
225             }
226              
227             sub _home {
228 37     37   153 my ($self, $args) = @_;
229 37 100       414 return Path::Tiny->new($args->{home}) if exists $args->{home};
230 15 100       91 return Path::Tiny->new($args->{ca_key})->parent(2) if $args->{ca_key};
231 12 50       197 return Path::Tiny->new($args->{key})->parent(2) if $args->{key};
232 0         0 croak '$SSLMAKER_HOME is required';
233             }
234              
235             sub _parse_subject {
236 25     25   222 my ($self, $val) = @_;
237 25 100       136 return $val if ref $val eq 'HASH';
238              
239             # /C=US/ST=Texas/L=Dallas/O=Company/OU=Department/CN=example.com/emailAddress=admin@example.com
240             # Subject: C = US, ST = Texas, L = Dallas, O = Company, OU = Department, CN = superduper
241 24 100       446 my $re = index($val, '/') == 0 ? qr{/([A-Za-z]+)=([^/]*)} : qr{([A-Za-z]+)\s*=\s*([^,]*)};
242 24         57 my %subject;
243 24         1465 $subject{$1} = $2 while $val =~ /$re/g;
244 24         280 return \%subject;
245             }
246              
247             sub _passphrase {
248 25     25   98 my ($self, $phrase) = @_;
249              
250 25 50 33     219 croak 'Parameter "passphrase" is required' unless defined $phrase and length $phrase;
251 25 50       385 return croak "SCALAR is not yet supported" if ref $phrase eq 'SCALAR';
252 25         95 return "file:$phrase";
253             }
254              
255             sub _random_passphrase {
256 8     8   347 my ($self, $length) = @_;
257 8         232 my @chr = ('a' .. 'z', 'A' .. 'Z', 0 .. 9);
258 8         51 join '', map { $chr[rand @chr] } 1 .. $length;
  511         1287  
259             }
260              
261             sub _read_subject_from_cert {
262 3     3   91 my ($self, $cert) = @_;
263 3         10 my %subject;
264              
265             # Subject: C = US, ST = Texas, L = Dallas, O = Company, OU = Department, CN = superduper
266             return openssl qw(x509 -noout -text -in), $cert => sub {
267 3     3   9 print STDERR $_[1] if DEBUG == 2 and length $_[1];
268 3 50       172 return $self->_parse_subject($1) if $_[1] =~ m!Subject:\s+(.+)!;
269 3         44 };
270              
271 0         0 die qq(Could not read subject from "$cert".);
272             }
273              
274             sub _render_subject {
275 18     18   111 my $self = shift;
276              
277 18         45 my %subject;
278 18         101 for my $i (@_) {
279 34 100       171 next unless $i;
280 25         40 $self->_d(qq(# Subject from @{[-r $i ? 'file' : 'data']} "$i")) if DEBUG == 2;
281 25 100       9684 my $s = -r $i ? $self->_read_subject_from_cert($i) : $self->_parse_subject($i);
282 25         148 map { $self->_d(sprintf '- %-12s %s', "$_:", "$s->{$_}") } sort keys %$s if DEBUG == 2;
283 25         530 $subject{$_} = $s->{$_} for keys %$s;
284             }
285              
286 18         61 return join '/', '', map {"$_=$subject{$_}"} grep { defined $subject{$_} } qw(C ST L O OU CN emailAddress);
  93         565  
  126         511  
287             }
288              
289             # used in script/sslmaker
290             sub _render_template {
291 49     49   119 my ($self, $name, $stash) = @_;
292 49   33     274 my $template = $DATA{$name} // confess "No such template: $name";
293 49   33     492 $template =~ s!<%=\s*([^%]+)\s*%>!{eval $1 // confess $@}!ges; # super cheap template parser
  205         6108  
  205         16860  
294 49         280 $template;
295             }
296              
297             1;
298              
299             =encoding utf8
300              
301             =head1 NAME
302              
303             App::sslmaker - Be your own SSL certificate authority
304              
305             =head1 DESCRIPTION
306              
307             L is a module that provide methods for acting as your own
308             L (certificate authority).
309             It can creating SSL keys, certificates and signing requests. The methods
310             should have good defaults and "just work", so you don't have to worry about
311             the details. "Just work" depends on safe defaults, which will change when
312             new and more secure standards come along.
313              
314             The openssl commands are based on the instructions from
315             L.
316              
317             This module is used by the C command line application, but can also
318             act as a standalone toolkit.
319              
320             =head1 DISCLAIMER
321              
322             This module is based on tips and tricks from online resources, and has been
323             reviewed by security experts. Even so, the L of this application or
324             any parts involved cannot be held responsible for the security of your
325             server, application or other parts that use the files generated by this
326             library.
327              
328             =head1 SYNOPSIS
329              
330             $ sslmaker [options]
331              
332             # 1. Initial CA setup
333             # 1a. The CA admin generates root CA key and certificate
334             $ sslmaker root --subject "/C=US/ST=Texas/L=Dallas/O=Company/OU=Department/CN=superduper"
335              
336             # 1b. The CA admin generates intermediate CA key and certificate
337             # Uses the --subject from root CA by default
338             $ sslmaker intermediate
339              
340             # 2. Client certificate setup
341             # 2a. The client generates a server key and certificate signing request
342             # Can be done on any other server
343             # Uses the --subject from intermediate CA if available
344             $ sslmaker generate
345             $ sslmaker generate www.example.com
346              
347             # 2b. The client sends the signing request file to the CA admin
348              
349             # 3. CA sign and revoke process
350             # 3a. The CA admin signs the certificate request
351             $ sslmaker sign www.example.com.csr.pem
352             $ sslmaker sign www.example.com.csr.pem [outfile]
353              
354             # 3b. The CA admin sends back the signed certificate which the client can use
355              
356             # 3c. The CA can revoke a certificate
357             $ sslmaker revoke
358             $ sslmaker revoke /etc/ssl/sslmaker/newcerts/1000.pem
359              
360             # 4. Utility commands
361             # 4a. Create dhparam file
362             $ sslmaker dhparam
363             $ sslmaker dhparam /etc/ssl/sslmaker/dhparam.pem 2048
364              
365             # 4b. Show the manual for App::sslmaker
366             $ sslmaker man
367              
368             =head1 ENVIRONMENT VARIABLES
369              
370             =over 2
371              
372             =item * SSLMAKER_BITS
373              
374             Default bits for a generated certificate. Default is 4096.
375              
376             =item * SSLMAKER_DAYS
377              
378             Default days before expiring a generated certificate. Default is 365.
379              
380             =item * SSLMAKER_DEBUG
381              
382             Setting this to "0" will output less debug information from C.
383              
384             =item * SSLMAKER_HOME
385              
386             Used by the C script as default home directory. Default is either
387             "/etc/pki/sslmaker" or "/etc/ssl/sslmaker".
388              
389             Directory structure is:
390              
391             # generated by "sslmaker root"
392             $SSLMAKER_HOME/root/ca.cert.pem
393             $SSLMAKER_HOME/root/ca.key.pem
394             $SSLMAKER_HOME/root/crlnumber
395             $SSLMAKER_HOME/root/index.txt
396             $SSLMAKER_HOME/root/index.txt.attr
397             $SSLMAKER_HOME/root/passphrase
398             $SSLMAKER_HOME/root/serial
399              
400             # generated by "sslmaker intermediate"
401             $SSLMAKER_HOME/certs/ca-chain.cert.pem
402             $SSLMAKER_HOME/certs/ca.cert.pem
403             $SSLMAKER_HOME/certs/ca.csr.pem
404             $SSLMAKER_HOME/private/ca.key.pem
405             $SSLMAKER_HOME/private/passphrase
406             $SSLMAKER_HOME/root/newcerts/1000.pem
407             $SSLMAKER_HOME/crlnumber
408             $SSLMAKER_HOME/index.txt
409             $SSLMAKER_HOME/index.txt.attr
410             $SSLMAKER_HOME/serial
411              
412             # generated by "sslmaker sign"
413             $SSLMAKER_HOME/newcerts/1000.pem
414              
415             # generated by "sslmaker dhparam"
416             $SSLMAKER_HOME/dhparam.pem
417              
418             NOTE! After running "sslmaker intermediate", then it is highly suggested to
419             move "$SSLMAKER_HOME/root/" to a safe location, such as a memory stick. You can
420             revoke any of the child certificates if they are compromised, but if you loose
421             the root key, then all is lost.
422              
423             =item * SSLMAKER_OPENSSL
424              
425             Default to "openssl". Can be set to a custom path if "openssl" is not in
426             C.
427              
428             =item * SSLMAKER_SUBJECT
429              
430             Used as default subject, unless specified.
431              
432             =back
433              
434             =head2 SEE ALSO
435              
436             =over 4
437              
438             =item * L
439              
440             =item * L
441              
442             =item * L
443              
444             =item * L
445              
446             =back
447              
448             =head1 METHODS
449              
450             =head2 make_cert
451              
452             $asset = $self->make_cert({
453             key => "/path/to/private/input.key.pem",
454             passphrase => "/path/to/passphrase.txt",
455             days => $number_of_days, # default: 365
456             subject => '/C=NO/ST=Oslo', # optional
457             ext => ["subjectAltName = DNS:example.com"], # optional
458             });
459              
460             This method will generate a SSL certificate using a C generated by
461             L. C should match the argument given to L.
462             An optional C can be provided. The subject string will be merged with the
463             L attribute. C can be used to set how many days the certificate
464             should be valid.
465              
466             The returned C<$asset> is a L object which holds the generated certificate
467             file. It is possible to specify the location of this object by passing on C to
468             this method.
469              
470             =head2 make_crl
471              
472             $asset = $self->make_crl({
473             key => "/path/to/private/input.key.pem",
474             cert => "/path/to/cefrt/input.cert.pem",
475             passphrase => "/path/to/passphrase.txt", # optional
476             });
477              
478             This method will generate a certificate revocation list (CRL) using a C generated
479             by L. C should match the argument given to L.
480              
481             The returned C<$asset> is a L object which holds the generated certificate
482             file. It is possible to specify the location of this object by passing on C to
483             this method.
484              
485             You can inspect the generated asset using the command
486             C.
487              
488             See also L.
489              
490             =head2 make_csr
491              
492             $asset = $self->make_csr({
493             key => "/path/to/private/input.key.pem",
494             passphrase => "/path/to/passphrase.txt",
495             subject => '/C=NO/ST=Oslo',
496             ext => ["subjectAltName=DNS:example.com"], # optional
497             });
498              
499             This method will generate a SSL certificate signing request using a C
500             generated by L. C is only required if the C was
501             generated with a C. An optional C can be provided.
502             The subject string will be merged with the L attribute.
503              
504             The returned C<$asset> is a L object which holds the generated
505             signing request file. It is possible to specify the location of this object
506             by passing on C to this method.
507              
508             =head2 make_directories
509              
510             $self->make_directories({
511             home => "/path/to/pki",
512             templates => 1, # default: false
513             });
514              
515             Used to generate a suitable file structure, which reflect what C
516             expects. Set C<$emplates> to a true value to generate L.
517              
518             $home/ # need to be writable by current user
519             $home/certs/
520             $home/crl/
521             $home/newcerts/
522             $home/private/ # will have mode 700
523             # optional templates
524             $home/index.txt
525             $home/serial
526              
527             =head2 make_key
528              
529             $asset = $self->make_key({
530             passphrase => "/path/to/passphrase.txt", # optional
531             bits => 8192, # default: 4096
532             });
533              
534             This method will generate a SSL key.
535              
536             The key will be protected with C if given as input. In addition
537             if C does not exist, it will be created with a random passphrase.
538              
539             The returned C<$asset> is a L object which holds the generated key.
540             It is possible to specify the location of this object by passing on C to
541             this method.
542              
543             =head2 new
544              
545             $self = App::sslmaker->new(%args);
546             $self = App::sslmaker->new(\%args);
547              
548             Object constructor.
549              
550             =head2 openssl
551              
552             $self->openssl(@args);
553             $self->openssl(@args, sub { ... });
554             App::sslmaker::openssl(@args);
555             App::sslmaker::openssl(@args, sub { ... });
556              
557             Used to run the application C. The callback defined at the end is
558             optional, but will be called with the complete output from the openssl
559             command. C<$?> is also available for inspection.
560              
561             The C application must exist in path or defined by setting the
562             C environment variable before loading this module.
563              
564             =head2 render_to_file
565              
566             $asset = $self->render_to_file($template, \%stash);
567             $asset = $self->render_to_file($template, $out_file, \%args);
568              
569             This method can render a C<$template> to either a temp file or C<$out_file>.
570             The C<$template> will have access to C<%stash> and C<$self>.
571              
572             See L for list of valid templates.
573              
574             =head2 revoke_cert
575              
576             $self->with_config(
577             revoke_cert => {
578             key => "/path/to/private/ca.key.pem",
579             cert => "/path/to/certs/ca.cert.pem",
580             crl => "/path/to/crl.pem",
581             revoke => "/path/to/newcerts/1000.pem",
582             },
583             );
584              
585             This method can revoke a certificate. It need to be run either with
586             C or inside L.
587              
588             =head2 sign_csr
589              
590             $asset = $self->sign_csr({
591             csr => "/path/to/certs/input.csr.pem",
592             ca_key => "/path/to/private/ca.key.pem",
593             ca_cert => "/path/to/certs/ca.cert.pem",
594             passphrase => "/path/to/passphrase.txt",
595             extensions => "v3_ca", # default: usr_cert
596             });
597              
598             This method will sign a C file generated by L. C and
599             C is the same values as you would provide L and
600             C is the output from L.
601              
602             The returned C<$asset> is a L object which holds the generated
603             certificate. It is possible to specify the location of this object by
604             passing on C to this method.
605              
606             =head2 subject
607              
608             $self = $self->subject(@subjects);
609             $self = $self->subject("/C=NO/ST=Oslo/L=Oslo/O=Example/OU=Prime/emailAddress=admin@example.com", ...);
610             $str = $self->subject;
611              
612             Holds the default subject field for the certificate. Can be set by passing in a
613             list of subject strings, hashes or paths to certificate files. The list will
614             get merged, soo the last one overrides the one before.
615              
616             =head2 with_config
617              
618             $any = $self->with_config($method => \%args);
619              
620             Used to call a L with a temp L
621             file. The C<%stash> in the template will be constructed from the C<%args>,
622             which is also passed on to the next C<$method>. Example:
623              
624             $asset = $self->with_config(make_key => {
625             home => "/path/to/pki",
626             passphrase => "/path/to/pki/private/passphrase.txt",
627             bits => 8192,
628             });
629              
630             The config file will be removed when C<$self> go out of scope.
631              
632             An alternative to this method is to set the C environment
633             variable before calling C<$method>:
634              
635             local $ENV{OPENSSL_CONF} = "/path/to/openssl.cnf";
636             $asset = $self->make_key({...});
637              
638             =head1 TEMPLATES
639              
640             L can render these templates, which is bundled with this module:
641              
642             =over 4
643              
644             =item * crlnumber
645              
646             Creates a file which stores the SSL CRL number. If C is present in
647             C<%stash>, it will be used as the start number, which defaults to 1000.
648              
649             =item * index.txt
650              
651             This is currently just an empty file.
652              
653             =item * nginx.config
654              
655             Used to render an example nginx config. C<%stash> should contain C,
656             C, C, C, C and C.
657              
658             =item * openssl.cnf
659              
660             Creates a config file for openssl. TODO: Descrive stash values.
661              
662             =item * serial
663              
664             Creates a file which stores the SSL serial number. If C is present in
665             C<%stash>, it will be used as the start number, which defaults to 1000.
666              
667             =back
668              
669             =head1 COPYRIGHT AND LICENCE
670              
671             =head2 Code
672              
673             Copyright (C) Jan Henning Thorsen
674              
675             The code is free software, you can redistribute it and/or modify it under the
676             terms of the Artistic License version 2.0.
677              
678             =head2 Documentation
679              
680             Documentation is licensed under the terms of Creative Commons
681             Attribution-ShareAlike 3.0 Unported license.
682              
683             The documentation is put together by Jan Henning Thorsen, with citations from
684             Jamie Nguyen's website L.
685              
686             =head1 AUTHOR
687              
688             Jan Henning Thorsen - C
689              
690             =cut
691              
692             __DATA__