[pmg-devel] [PATCH pmg-api 1/1] fix #2504: do not overwrite existing selector key

Stoiko Ivanov s.ivanov at proxmox.com
Thu Dec 5 14:01:42 CET 2019


This patch changes the behavior of DKIM selector creation. Instead of blindly
overwriting an already present file, add a force parameter to overwrite it (and
behave like the current code).

Overwriting an existing selector can potentially be quite destructive (e.g.
a setup where the admin has already posted the DNS-record for one selector to
many domains, then wants to quickly experiment with a larger keysize, and tries
to go back to the existing behavior).

The new behavior without force set to true, when a private key for the selector
already exists is to die if the file is either not a private RSA key, or has
the wrong size, or else just set the selector in pmg.conf

Signed-off-by: Stoiko Ivanov <s.ivanov at proxmox.com>
---
 src/PMG/API2/DKIMSign.pm |  7 ++++++-
 src/PMG/DKIMSign.pm      | 23 ++++++++++++++++++-----
 2 files changed, 24 insertions(+), 6 deletions(-)

diff --git a/src/PMG/API2/DKIMSign.pm b/src/PMG/API2/DKIMSign.pm
index 8e2d85b..9aad2e2 100644
--- a/src/PMG/API2/DKIMSign.pm
+++ b/src/PMG/API2/DKIMSign.pm
@@ -65,6 +65,10 @@ __PACKAGE__->register_method({
 		description => "Number of bits for the RSA-Key",
 		type => 'integer', minimum => 1024
 	    },
+	    force => {
+		description => "Overwrite existing key",
+		type => 'boolean', optional => 1, default => 1
+	    },
 	},
     },
     returns => { type => 'null' },
@@ -72,8 +76,9 @@ __PACKAGE__->register_method({
 	my ($param) = @_;
 	my $selector = extract_param($param, 'selector');
 	my $keysize = extract_param($param, 'keysize');
+	my $force = extract_param($param, 'force');
 
-	PMG::DKIMSign::set_selector($selector, $keysize);
+	PMG::DKIMSign::set_selector($selector, $keysize, $force);
 
 	return undef;
     }});
diff --git a/src/PMG/DKIMSign.pm b/src/PMG/DKIMSign.pm
index 5810cea..094e0d9 100644
--- a/src/PMG/DKIMSign.pm
+++ b/src/PMG/DKIMSign.pm
@@ -157,22 +157,35 @@ sub get_selector_info {
 }
 
 sub set_selector {
-    my ($selector, $keysize) = @_;
+    my ($selector, $keysize, $force) = @_;
 
     die "no selector provided\n" if !defined($selector);
     die "no keysize provided\n" if !defined($keysize);
     die "invalid keysize\n" if ($keysize < 1024);
     my $privkey_file = "/etc/pmg/dkim/$selector.private";
 
-    my $code = sub{
-	my $cmd = ['openssl', 'genrsa', '-out', $privkey_file, $keysize];
-	PMG::Utils::run_silent_cmd($cmd);
+    my $code = sub {
+	my $genkey = $force || (! -e $privkey_file);
+	if (!$genkey) {
+	    my ($privkeytext, $privkey, $cursize);
+	    eval {
+		$privkeytext = PVE::Tools::file_get_contents($privkey_file);
+		$privkey =  Crypt::OpenSSL::RSA->new_private_key($privkeytext);
+		$cursize = $privkey->size() * 8;
+	    };
+	    die "$privkey_file exists but is not a valid key.\n" if $@;
+	    die "$privkey_file already exists, but has different size ($cursize bits)\n"
+		if $cursize != $keysize;
+	} else {
+	    my $cmd = ['openssl', 'genrsa', '-out', $privkey_file, $keysize];
+	    PMG::Utils::run_silent_cmd($cmd);
+	}
 	my $cfg = PMG::Config->new();
 	$cfg->set('admin', 'dkim_selector', $selector);
 	$cfg->write();
 	PMG::Utils::reload_smtp_filter();
     };
 
-    PMG::Config::lock_config($code, "unable to generate DKIM key ($selector - $keysize bits)");
+    PMG::Config::lock_config($code, "unable to set DKIM key ($selector - $keysize bits)");
 }
 1;
-- 
2.20.1




More information about the pmg-devel mailing list