File Coverage

blib/lib/App/sslmaker.pm
Criterion Covered Total %
statement 167 170 98.2
branch 60 82 73.1
condition 25 42 59.5
subroutine 33 33 100.0
pod 12 12 100.0
total 297 339 87.6


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