diff --git a/webmin/lang/en b/webmin/lang/en index d639844c1..63b4db282 100644 --- a/webmin/lang/en +++ b/webmin/lang/en @@ -341,7 +341,7 @@ ssl_hole=Because you are currently using the default Webmin SSL key that everyon ssl_header1=Create SSL key ssl_header2=Create SSL CSR ssl_create=Create Now -ssl_cn=Server name +ssl_cn=Server names ssl_all=Any hostname ssl_newfile=Write key to file ssl_csrfile=Write CSR to file @@ -411,6 +411,7 @@ ssl_letsnotrenew=Only renew manually newkey_err=Failed to create SSL key newkey_ecn=Missing or invalid server name +newkey_ecns=No server names entered newkey_efile=Missing key file name newkey_title=Generate Key newkey_ecmd=The SSL command $1 was not found on your system. Either it is not installed, or the Webmin Users module configuration is incorrect. diff --git a/webmin/letsencrypt-lib.pl b/webmin/letsencrypt-lib.pl index 01095fc2b..08e78b8a8 100644 --- a/webmin/letsencrypt-lib.pl +++ b/webmin/letsencrypt-lib.pl @@ -103,7 +103,7 @@ else { # Generate a CSR my $csr = &transname(); my ($ok, $csr) = &generate_ssl_csr($key, undef, undef, undef, - undef, undef, $doms[0], undef); + undef, undef, \@doms, undef); if (!$ok) { return &text('letsencrypt_ecsr', $csr); } diff --git a/webmin/webmin-lib.pl b/webmin/webmin-lib.pl index 064f458c4..f4390d998 100755 --- a/webmin/webmin-lib.pl +++ b/webmin/webmin-lib.pl @@ -1879,34 +1879,34 @@ my ($defhost, $defemail, $deforg) = @_; my $rv; $rv .= &ui_table_row($text{'ssl_cn'}, - &ui_opt_textbox("commonName", $defhost, 30, - $text{'ssl_all'}), undef, [ "valign=middle","valign=middle" ]); + &ui_opt_textbox("commonName", $defhost, 50, + $text{'ssl_all'})); $rv .= &ui_table_row($text{'ca_email'}, - &ui_textbox("emailAddress", $defemail, 30), undef, [ "valign=middle","valign=middle" ]); + &ui_textbox("emailAddress", $defemail, 30)); $rv .= &ui_table_row($text{'ca_ou'}, - &ui_textbox("organizationalUnitName", undef, 30), undef, [ "valign=middle","valign=middle" ]); + &ui_textbox("organizationalUnitName", undef, 30)); $rv .= &ui_table_row($text{'ca_o'}, - &ui_textbox("organizationName", $deforg, 30), undef, [ "valign=middle","valign=middle" ]); + &ui_textbox("organizationName", $deforg, 30)); $rv .= &ui_table_row($text{'ca_city'}, - &ui_textbox("cityName", undef, 30), undef, [ "valign=middle","valign=middle" ]); + &ui_textbox("cityName", undef, 30)); $rv .= &ui_table_row($text{'ca_sp'}, - &ui_textbox("stateOrProvinceName", undef, 15), undef, [ "valign=middle","valign=middle" ]); + &ui_textbox("stateOrProvinceName", undef, 15)); $rv .= &ui_table_row($text{'ca_c'}, - &ui_textbox("countryName", undef, 2), undef, [ "valign=middle","valign=middle" ]); + &ui_textbox("countryName", undef, 2)); $rv .= &ui_table_row($text{'ssl_size'}, &ui_opt_textbox("size", undef, 6, "$text{'default'} ($default_key_size)"). - " ".$text{'ssl_bits'}, undef, [ "valign=middle","valign=middle" ]); + " ".$text{'ssl_bits'}); $rv .= &ui_table_row($text{'ssl_days'}, - &ui_textbox("days", 1825, 8), undef, [ "valign=middle","valign=middle" ]); + &ui_textbox("days", 1825, 8)); return $rv; } @@ -1923,8 +1923,14 @@ my ($in, $keyfile, $certfile) = @_; my %in = %$in; # Validate inputs -$in{'commonName_def'} || $in{'commonName'} =~ /^[A-Za-z0-9\.\-\*]+$/ || - return $text{'newkey_ecn'}; +my @cns; +if (!$in{'commonName_def'}) { + @cns = split(/\s+/, $in{'commonName'}); + @cns || return $text{'newkey_ecns'}; + foreach my $cn (@cns) { + $cn =~ /^[A-Za-z0-9\.\-\*]+$/ || return $text{'newkey_ecn'}; + } + } $in{'size_def'} || $in{'size'} =~ /^\d+$/ || return $text{'newkey_esize'}; $in{'days'} =~ /^\d+$/ || return $text{'newkey_edays'}; $in{'countryName'} =~ /^\S\S$/ || return $text{'newkey_ecountry'}; @@ -1996,8 +2002,17 @@ my ($in, $keyfile, $csrfile) = @_; my %in = %$in; # Validate inputs -$in{'commonName_def'} || $in{'commonName'} =~ /^[A-Za-z0-9\.\-\*]+$/ || - return $text{'newkey_ecn'}; +my @cns; +if (!$in{'commonName_def'}) { + @cns = split(/\s+/, $in{'commonName'}); + @cns || return $text{'newkey_ecns'}; + foreach my $cn (@cns) { + $cn =~ /^[A-Za-z0-9\.\-\*]+$/ || return $text{'newkey_ecn'}; + } + } +else { + @cns = ( "*" ); + } $in{'size_def'} || $in{'size'} =~ /^\d+$/ || return $text{'newkey_esize'}; $in{'days'} =~ /^\d+$/ || return $text{'newkey_edays'}; $in{'countryName'} =~ /^\S\S$/ || return $text{'newkey_ecountry'}; @@ -2027,7 +2042,7 @@ my ($ok, $ctemp) = &generate_ssl_csr( $in{'cityName'}, $in{'organizationName'}, $in{'organizationalUnitName'}, - $in{'commonName_def'} ? "*" : $in{'commonName'}, + \@cns, $in{'emailAddress'}); if (!$ok) { return $text{'newkey_essl'}."
". @@ -2052,7 +2067,31 @@ my ($kfh, $cfh); return undef; } -# generate_ssl_csr(keyfile, country, state, city, org, orgunit, cname, email) +# build_ssl_subject(country, state, city, org, orgunit, cname|&cnames, email) +# Generate a full subject line suitable for use with the -subj parameter +sub build_ssl_subject +{ +my ($country, $state, $city, $org, $orgunit, $cn, $email) = @_; +my @cns = ref($cn) ? @$cn : ( $cn ); +my $subject; +$subject .= "/C=$country" if ($country); +$subject .= "/ST=$state" if ($state); +$subject .= "/L=$city" if ($city); +$subject .= "/O=$org" if ($org); +$subject .= "/OU=$orgunit" if ($orgunit); +$subject .= "/CN=$cns[0]"; +$subject .= "/emailAddress=$email" if ($email); +if (@cns > 1) { + my @sans; + for(my $i=1; $i<@cns; $i++) { + push(@sans, "DNS.".$i."=".$cns[$i]); + } + $subject .= "/subjectAltName=".join(",", @sans); + } +return $subject; +} + +# generate_ssl_csr(keyfile, country, state, city, org, orgunit, cname|&cnames, email) # Generates a new CSR, and returns either 1 and the temp file path, or 0 and # an error message sub generate_ssl_csr @@ -2062,21 +2101,11 @@ my ($ktemp, $country, $state, $city, $org, $orgunit, $cn, $email) = @_; my $ctemp = &transname(); my $outtemp = &transname(); my $cmd = &acl::get_ssleay(); -open(CA, "| $cmd req -new -key $ktemp -out $ctemp >$outtemp 2>&1"); -print CA ($country || "."),"\n"; -print CA ($state || "."),"\n"; -print CA ($city || "."),"\n"; -print CA ($org || "."),"\n"; -print CA ($orgunit || "."),"\n"; -print CA ($cn || "."),"\n"; -print CA ($email || "."),"\n"; -print CA ".\n"; -print CA ".\n"; -close(CA); -my $rv = $?; -my $out = &read_file_contents($outtemp); -unlink($outtemp); -if (!-r $ctemp || $rv) { +my $subject = &build_ssl_subject($country, $state, $city, $org, $orgunit, $cn,$email); +my $out = &backquote_command( + "$cmd req -new -key $ktemp -out $ctemp -sha256 ". + "-subj ".quotemeta($subject)." 2>&1"); +if (!-r $ctemp || $?) { return (0, $out); } else {