7 use File::Temp qw(tempdir); |
7 use File::Temp qw(tempdir); |
8 use File::Basename; |
8 use File::Basename; |
9 use Getopt::Long qw(GetOptionsFromArray); |
9 use Getopt::Long qw(GetOptionsFromArray); |
10 use Pod::Usage; |
10 use Pod::Usage; |
11 |
11 |
12 my $CA_CRT = "CA/ca-crt.pem"; |
12 my $CA_CRT = "CA/ca-crt.pem"; |
13 my $CA_KEY = "CA/private/ca-key.pem"; |
13 my $CA_KEY = "CA/private/ca-key.pem"; |
14 my $CA_DIR = "./var"; |
14 my $CA_DIR = "./var"; |
15 |
15 |
16 my %TEMPLATE = ( |
16 my %TEMPLATE = ( |
17 ca => "templates/ca", |
17 ca => "templates/ca", |
18 req => "templates/req", |
18 req => "templates/req", |
19 ); |
19 ); |
20 |
20 |
21 my $TMP = tempdir("/tmp/$ENV{USER}.ca.XXXXXX", CLEANUP => 1); |
21 my $TMP = tempdir("/tmp/$ENV{USER}.ca.XXXXXX", CLEANUP => 1); |
22 |
22 |
23 my $opt_days = undef; # see the templates/ca for a default |
23 my $opt_days = undef; # see the templates/ca for a default |
24 my $opt_type = undef; # see the templates/ca for a default |
24 my $opt_type = undef; # see the templates/ca for a default |
25 my $opt_policy = "de"; # see the templates/ca for a default |
25 my $opt_policy = "de"; # see the templates/ca for a default |
26 my $opt_outfile = undef; |
26 my $opt_outfile = undef; |
27 my $opt_force = undef; |
27 my $opt_force = undef; |
28 |
28 |
29 sub init_ca(); |
29 sub init_ca(); |
30 sub ask_pass($); |
30 sub ask_pass($); |
31 |
31 |
32 MAIN: { |
32 MAIN: { |
35 GetOptions( |
35 GetOptions( |
36 "d|days=i" => \$opt_days, |
36 "d|days=i" => \$opt_days, |
37 "t|type=s" => \$opt_type, |
37 "t|type=s" => \$opt_type, |
38 "p|policy=s" => \$opt_policy, |
38 "p|policy=s" => \$opt_policy, |
39 "o|outfile=s" => \$opt_outfile, |
39 "o|outfile=s" => \$opt_outfile, |
40 "force" => \$opt_force, |
40 "force" => \$opt_force, |
41 "init" => sub { init_ca(); exit 0; }, |
41 "init" => sub { init_ca(); exit 0; }, |
42 "h|help" => sub { pod2usage(-verbose => 1, -exit => 0) }, |
42 "h|help" => sub { pod2usage(-verbose => 1, -exit => 0) }, |
43 "m|man" => sub { pod2usage(-verbose => 2, -exit => 0) }, |
43 "m|man" => sub { pod2usage(-verbose => 2, -exit => 0) }, |
44 ) or pod2usage; |
44 ) or pod2usage; |
45 |
45 |
46 pod2usage if @ARGV > 1; |
46 pod2usage if @ARGV > 1; |
104 sub ask_pass($) { |
104 sub ask_pass($) { |
105 my $prompt = shift; |
105 my $prompt = shift; |
106 my @keys = ("x", "y"); |
106 my @keys = ("x", "y"); |
107 |
107 |
108 while (1) { |
108 while (1) { |
109 print $prompt; |
109 print $prompt; |
110 my $stty = `stty -g`; |
110 my $stty = `stty -g`; |
111 system("stty -echo"); |
111 system("stty -echo"); |
112 chomp($keys[0] = IO::File->new("/dev/tty")->getline()); |
112 chomp($keys[0] = IO::File->new("/dev/tty")->getline()); |
113 print "\n"; |
113 print "\n"; |
114 system("stty $stty"); |
114 system("stty $stty"); |
115 print "please again for verification: "; |
115 print "please again for verification: "; |
116 system("stty -echo"); |
116 system("stty -echo"); |
117 chomp($keys[1] = IO::File->new("/dev/tty")->getline()); |
117 chomp($keys[1] = IO::File->new("/dev/tty")->getline()); |
118 print "\n"; |
118 print "\n"; |
119 system("stty $stty"); |
119 system("stty $stty"); |
120 return $keys[0] if $keys[0] eq $keys[1]; |
120 return $keys[0] if $keys[0] eq $keys[1]; |
121 print "keys mismatch, again\n"; |
121 print "keys mismatch, again\n"; |
122 } |
122 } |
123 } |
123 } |
124 |
124 |
125 sub init_ca() { |
125 sub init_ca() { |
|
126 |
126 # initialize the CA directory structure. This should |
127 # initialize the CA directory structure. This should |
127 # correspond to the values found in templates/ca |
128 # correspond to the values found in templates/ca |
128 die "$CA_DIR already exists" if -d $CA_DIR and not $opt_force; |
129 die "$CA_DIR already exists" if -d $CA_DIR and not $opt_force; |
129 mkpath(map { "$CA_DIR/$_" } qw(newcerts)); |
130 mkpath(map { "$CA_DIR/$_" } qw(newcerts)); |
130 mkpath(map { dirname $_ } $CA_CRT, $CA_KEY); |
131 mkpath(map { dirname $_ } $CA_CRT, $CA_KEY); |
131 (new IO::File ">$CA_DIR/index"); |
132 (new IO::File ">$CA_DIR/index"); |
132 (new IO::File ">$CA_DIR/serial")-> print("01\n"); |
133 (new IO::File ">$CA_DIR/serial")->print("01\n"); |
133 |
134 |
134 # now |
135 # now |
135 my $tt2 = new Template or die $Template::ERROR; |
136 my $tt2 = new Template or die $Template::ERROR; |
136 $tt2->process($TEMPLATE{req}, |
137 $tt2->process( |
137 { |
138 $TEMPLATE{req}, |
138 # not used yet |
139 { |
139 } => "$TMP/cnf") or die $tt2->error; |
140 |
|
141 # not used yet |
|
142 } => "$TMP/cnf" |
|
143 ) or die $tt2->error; |
140 |
144 |
141 $ENV{CA_PASS} = ask_pass("passphrase for CA key: "); |
145 $ENV{CA_PASS} = ask_pass("passphrase for CA key: "); |
142 system("openssl req -config $TMP/cnf -x509 -days 3650 -new -passout env:CA_PASS -keyout $TMP/ca-key.pem -out $TMP/ca-crt.pem") |
146 system( |
143 and exit; |
147 "openssl req -config $TMP/cnf -x509 -days 3650 -new -passout env:CA_PASS -keyout $TMP/ca-key.pem -out $TMP/ca-crt.pem" |
|
148 ) and exit; |
144 |
149 |
145 system("openssl x509 -in $TMP/ca-crt.pem -out $CA_CRT") and exit; |
150 system("openssl x509 -in $TMP/ca-crt.pem -out $CA_CRT") and exit; |
146 $_ = umask(077); |
151 $_ = umask(077); |
147 system("openssl rsa -in $TMP/ca-key.pem -des3 -passin env:CA_PASS -passout env:CA_PASS -out $CA_KEY") and exit; |
152 system( |
|
153 "openssl rsa -in $TMP/ca-key.pem -des3 -passin env:CA_PASS -passout env:CA_PASS -out $CA_KEY" |
|
154 ) and exit; |
148 umask($_); |
155 umask($_); |
149 |
|
150 |
156 |
151 } |
157 } |
152 |
158 |
153 __END__ |
159 __END__ |
154 |
160 |