diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2018-02-09 12:11:18 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2018-02-09 12:18:16 +0200 |
commit | c95c16005cb6ffafd27e884c405b839e049384a6 (patch) | |
tree | 536c2895b923e4eb539d254a4ba7b5568bdb513f | |
parent | 70922eff7611175811958174e0c5ba45948bb118 (diff) | |
download | acmeman-c95c16005cb6ffafd27e884c405b839e049384a6.tar.gz acmeman-c95c16005cb6ffafd27e884c405b839e049384a6.tar.bz2 |
Use configurable key length.
* acmeman: (syntax) New configuration settings: core.key-size and
domain.*.key-size.
(make_csr): Take the key size as 2nd argument.
(domain_cert_expires): Determine key size from the configuration. Include
it in the debug output.
(coalesce): Bugfix.
* lib/App/Acmeman/Apache/Layout.pm (apache_layout_tab): Additional tests
to resolve ambuguities.
(new): Use the _test field to resolve ambiguities.
* lib/App/Acmeman/Source/Apache.pm (server_root): New method.
(http_include): Determine the server root by probing the server, unless
it is set explicitly in the configuration.
(probe): New method.
-rwxr-xr-x | acmeman | 43 | ||||
-rw-r--r-- | lib/App/Acmeman/Apache/Layout.pm | 5 | ||||
-rw-r--r-- | lib/App/Acmeman/Source/Apache.pm | 54 |
3 files changed, 84 insertions, 18 deletions
@@ -233,6 +233,10 @@ underlying X509 module, and therefore is not enabled by default. Valid values for I<BOOL> are: B<1>, B<on>, B<true>, or B<yes>, for true, and B<0>, B<off>, B<false>, or B<no> for false (all values case-insensitive). + +=item B<key-size=>I<N> + +Size of the RSA key to use, in bits. Default is 4096. =back @@ -254,6 +258,11 @@ statement from the B<[core]> section will be used. Defines alternative name for the certificate. Multiple B<alt> statements are allowed. + +=item B<key-size=>I<N> + +Size of the RSA key to use, in bits. If not set, the B<core.key-size> +setting is used. =back @@ -598,8 +607,8 @@ sub debug_to_loglevel { } sub make_csr { - my $dom = shift; - my $req = Crypt::OpenSSL::PKCS10->new(4096); + my ($dom, $keysize) = @_; + my $req = Crypt::OpenSSL::PKCS10->new($keysize); $req->set_subject("/CN=".$dom->cn); $req->add_ext(Crypt::OpenSSL::PKCS10::NID_subject_alt_name, join(',', map { "DNS:$_" } $dom->alt)) @@ -698,17 +707,22 @@ sub domain_cert_expires { sub register_domain_certificate { my $domain = shift; + my $key_size = $config->get('domain', $domain, 'key-size') + || $config->get('core', 'key-size'); + if ($debug) { my $crt = $domain->certificate_file; my $alt = join(',', $domain->alt); if (-f $crt) { - debug(1, "renewing $crt: CN=$domain, alternatives=$alt"); + debug(1, "renewing $crt: CN=$domain, alternatives=$alt, key_size=$key_size"); } else { - debug(1, "issuing $crt: CN=$domain, alternatives=$alt"); + debug(1, "issuing $crt: CN=$domain, alternatives=$alt, key_size=$key_size"); } } + return 1 if $dry_run; - + $account_key = Crypt::OpenSSL::RSA->generate_key($key_size); + my $acme = Protocol::ACME->new( host => $acme_endpoint{$acme_host}, account_key => { buffer => $account_key->get_private_key_string(), format => 'PEM' }, @@ -727,7 +741,7 @@ sub register_domain_certificate { $acme->cleanup_challenge($challenge); } - my $csr = make_csr($domain); + my $csr = make_csr($domain, $key_size); my $cert = $acme->sign({ format => 'PEM', buffer => $csr->get_pem_req() }); my $chain = $acme->chain(); @@ -826,7 +840,7 @@ sub coalesce { my @domlist; foreach my $ent (sort { $a->{domain} cmp $b->{domain} } map { { ord => $i++, domain => $_ } } @{$ref}) { - if (@domlist && $domlist[-1]->cn eq $ent->cn) { + if (@domlist && $domlist[-1]->{domain}->cn eq $ent->{domain}->cn) { $domlist[-1] += $ent; } else { push @domlist, $ent; @@ -842,7 +856,7 @@ sub collect { while (my ($k, $v) = each %{$config->get('domain')}) { my $dom; my $ft; - + if (exists($v->{files})) { if (my $fref = $config->get('files', $v->{files})) { $dom = new App::Acmeman::Domain( @@ -917,8 +931,9 @@ my %syntax = ( rootdir => { default => '/var/www/acme' }, files => 1, 'time-delta' => { default => 86400 }, - source => 1, - 'check-alt-names' => { default => 0, parser => \&cb_check_bool } + source => { default => 'apache' }, + 'check-alt-names' => { default => 0, parser => \&cb_parse_bool }, + 'key-size' => { re => '^\d+$', default => 4096 } } }, files => { @@ -939,7 +954,8 @@ my %syntax = ( '*' => { section => { alt => { array => 1 }, - files => 1 + files => 1, + 'key-size' => { re => '^\d+$' } } } } @@ -1013,8 +1029,10 @@ my @domlist; $config = new App::Acmeman::Config($config_file, syntax => \%syntax, defaults => { - 'core.source' => 'apache' + 'core.source' => 'apache', + 'core.key-size' => 4096, }); + if ($config->success) { if (my $source = $config->get(qw(core source))) { my ($name, @args) = quotewords('\s+', 0, $source); @@ -1057,7 +1075,6 @@ prep_dir($config->get(qw(core rootdir)).'/file'); # abend(EX_CONFIG, "filename patterns not defined") # unless (defined($filename_arg) && defined($filename_pattern{cert})); -$account_key = Crypt::OpenSSL::RSA->generate_key(4096); $challenge = Protocol::ACME::Challenge::LocalFile->new({ www_root => $config->get(qw(core rootdir)) }); diff --git a/lib/App/Acmeman/Apache/Layout.pm b/lib/App/Acmeman/Apache/Layout.pm index 77e2f8f..44d5e3d 100644 --- a/lib/App/Acmeman/Apache/Layout.pm +++ b/lib/App/Acmeman/Apache/Layout.pm @@ -10,6 +10,7 @@ our @ISA = qw(Exporter); my %apache_layout_tab = ( slackware => { + _test => sub { -d '/etc/httpd/extra' }, _config_file => '/etc/httpd/httpd.conf', _incdir => '/etc/httpd/extra', _restart => '/etc/rc.d/rc.httpd restart' @@ -42,6 +43,7 @@ my %apache_layout_tab = ( }, suse => { _config_file => '/etc/apache2/httpd.conf', + _test => sub { ! -f '/etc/apache2/apache2.conf' }, _incdir => '/etc/apache2/conf.d', _restart => 'service httpd restart' # or systemctl restart apache2.service @@ -59,6 +61,9 @@ sub new { # Autodetect while (my ($n, $layout) = each %apache_layout_tab) { if (-f $layout->{_config_file}) { + if (exists($layout->{_test}) && !&{$layout->{_test}}) { + next; + } debug(2, "assuming Apache layout \"$n\""); $name = $n; last; diff --git a/lib/App/Acmeman/Source/Apache.pm b/lib/App/Acmeman/Source/Apache.pm index f86c02f..c4a0570 100644 --- a/lib/App/Acmeman/Source/Apache.pm +++ b/lib/App/Acmeman/Source/Apache.pm @@ -5,6 +5,8 @@ use warnings; use Carp; use feature 'state'; use File::Path qw(make_path); +use File::Spec; +use IPC::Open3; require App::Acmeman::Apache::Layout; our @ISA = qw(App::Acmeman::Apache::Layout); @@ -84,7 +86,7 @@ sub examine_http_config { s/^\s+//; next if /^(#.*)?$/; if (/^include(optional)?\s+(.+?)\s*$/i) { -# debug(3, "$file:$line: state $state: Include$1 $2"); + #debug(3, "$file:$line: state $state: Include".($1||'')." $2"); $self->http_include($self->dequote($2), defined($1)); next; } @@ -96,7 +98,7 @@ sub examine_http_config { @server_aliases = (); $reference = undef; } elsif (/^ServerRoot\s+(.+)/i) { - $self->{_server_root} = $self->dequote($1); + $self->server_root($self->dequote($1)); } elsif (/^<(?:(?i)Macro)\s+LetsEncryptChallenge/) { $state = STATE_MACRO_CHALLENGE; } elsif (/^<(?:(?i)Macro)\s+LetsEncryptSSL\s+(.+?)\s*>/) { @@ -181,11 +183,25 @@ sub examine_http_config { return 1; } +sub server_root { + my $self = shift; + if (my $v = shift) { + croak "too many arguments" if $@; + $self->{_server_root} = $v; + } + return $self->{_server_root}; +} + sub http_include { my ($self, $pattern, $optional) = @_; - $pattern = "$self->{_server_root}/$pattern" unless $pattern =~ m{^/}; - $pattern =~ s{/*$}{}; - $pattern .= '/*' if -d $pattern; + + unless ($self->server_root) { + $self->probe; + } + + $pattern = File::Spec->catfile($self->{_server_root}, $pattern) + unless $pattern =~ m{^/}; + $pattern = File::Spec->catfile($pattern, '*') if -d $pattern; foreach my $file (glob $pattern) { if ($optional && ! -e $file) { debug(1, "optional include file \"$file\" doesn't exist"); @@ -281,4 +297,32 @@ EOT return 1; } +sub probe { + my ($self, @servlist) = @_; + @servlist = qw(/usr/sbin/httpd /usr/sbin/apache2) + unless (@servlist); + open(my $nullout, '>', File::Spec->devnull); + open(my $nullin, '<', File::Spec->devnull); + foreach my $serv (@servlist) { + use Symbol 'gensym'; + my $fd = gensym; + eval { + if (my $pid = open3($nullin, $fd, $nullout, $serv, '-V')) { + while (<$fd>) { + chomp; + if (/^\s+-D\s+HTTPD_ROOT=(.+)\s*$/) { + $self->server_root($self->dequote($1)); + last; + } + } + } + }; + close $fd; + last unless ($@) + } + close $nullin; + close $nullout; +} + + 1; |