apache2-mod_nss/mod_nss_migrate.pl
Wolfgang Rosenauer 1d3e419a19 Accepting request 222758 from home:draht:branches:mozilla:Factory
- mod_nss-cipherlist_update_for_tls12-doc.diff
  mod_nss-cipherlist_update_for_tls12.diff
  GCM mode and Camellia ciphers added to the supported ciphers list.
  The additional ciphers are: 
  rsa_aes_128_gcm_sha == TLS_RSA_WITH_AES_128_GCM_SHA256
  rsa_camellia_128_sha == TLS_RSA_WITH_CAMELLIA_128_CBC_SHA
  rsa_camellia_256_sha == TLS_RSA_WITH_CAMELLIA_256_CBC_SHA
  ecdh_ecdsa_aes_128_gcm_sha == TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256
  ecdhe_ecdsa_aes_128_gcm_sha == TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
  ecdh_rsa_aes_128_gcm_sha == TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256
  ecdhe_rsa_aes_128_gcm_sha == TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
  [bnc#863035]

- mod_nss-CVE-2013-4566-NSSVerifyClient.diff fixes CVE-2013-4566:
  If 'NSSVerifyClient none' is set in the server / vhost context
  (i.e. when server is configured to not request or require client
  certificate authentication on the initial connection), and client
  certificate authentication is expected to be required for a 
  specific directory via 'NSSVerifyClient require' setting, 
  mod_nss fails to properly require certificate authentication.
  Remote attacker can use this to access content of the restricted
  directories. [bnc#853039]

- glue documentation added to /etc/apache2/conf.d/mod_nss.conf:
  * simultaneaous usage of mod_ssl and mod_nss
  * SNI concurrency
  * SUSE framework for apache configuration, Listen directive
  * module initialization
- mod_nss-conf.patch obsoleted by scratch-version of nss.conf.in
  or mod_nss.conf, respectively. This also leads to the removal of

OBS-URL: https://build.opensuse.org/request/show/222758
OBS-URL: https://build.opensuse.org/package/show/mozilla:Factory/apache2-mod_nss?expand=0&rev=8
2014-02-20 21:12:44 +00:00

397 lines
13 KiB
Perl

#!/usr/bin/perl
#
# Migrate configuration from OpenSSL to NSS
use Cwd;
use Getopt::Std;
BEGIN {
# $NSSDir = cwd();
$NSSDir = "/etc/apache2/mod_nss.d";
$SSLCACertificatePath = "";
$SSLCACertificateFile = "";
$SSLCertificateFile = "";
$SSLCARevocationPath = "";
$SSLCARevocationFile = "";
$SSLCertificateKeyFile = "";
$passphrase = 0;
}
%skip = ( "SSLRandomSeed" => "",
"SSLSessionCache" => "",
"SSLMutex" => "",
"SSLCertificateChainFile" => "",
"SSLVerifyDepth" => "" ,
"SSLCryptoDevice" => "" ,
"LoadModule" => "" ,
);
%insert = ( "NSSSessionCacheTimeout", "NSSSessionCacheSize 10000\nNSSSession3CacheTimeout 86400\n",);
getopts('chr:w:' , \%opt );
sub usage() {
print STDERR "Usage: mod_nss_migrate.pl [-c] -r <mod_ssl input file> -w <mod_nss output file>\n";
print STDERR "\t-c converts the certificates\n";
print STDERR "This conversion script is not aware of apache's configuration blocks\n";
print STDERR "and nestable conditional directives. Please check the output of the\n";
print STDERR "conversion and adjust manually if necessary!\n";
exit();
}
usage() if ( $opt{h} || !$opt{r} || !$opt{w} ) ;
print STDERR "input: $opt{r} output: $opt{w}\n";
open (SSL, "<", $opt{r} ) or die "Unable to open $opt{r}: $!.\n";
open (NSS, ">", $opt{w} ) or die "Unable to open $opt{w}: $!.\n";
print NSS "## This is a conversion of mod_ssl specific options by /usr/sbin/mod_nss_migrate.pl\n";
print NSS "## Most of the comments in the original .conf file have been omitted here, as\n";
print NSS "## the comments may not be valid for mod_nss, too.\n";
print NSS "## \n";
print NSS "## Please read through this configuration and verify the individual options!\n\n";
while (<SSL>) {
my $comment = 0;
# write through even if in comment before comments are stripped below.
if(/(ServerName|ServerAlias)/) {
print NSS $_;
next;
}
# skip blank lines and comments
if (/^#/ || /^\s*#/ || /^\s*$/) {
# do not copy them; they may not be useful anyway.
# print NSS $_;
next;
}
s/mod_ssl\.c/mod_nss.c/;
# write through nestable apache configuration block directives:
if (/^</ || /^\s</) {
print NSS $_;
next;
}
m/(\w+)\s+(.+)/;
$stmt = $1;
$value = $2;
# Handle the special cases
if ($stmt eq "SSLVerifyClient" && $value eq "optional_no_ca") {
print NSS "# Replaced optional_no_ca with optional\n";
print NSS "SSLVerifyClient optional\n";
next;
}
if ($stmt eq "SSLCipherSuite") {
print NSS "## original SSLCipherSuite config line: $_";
print NSS "NSSCipherSuite ", get_ciphers($val), "\n\n";
next;
} elsif ($stmt eq "SSLEngine" ) {
print NSS "##$_";
print NSS "NSSEngine $value\n\n";
next;
} elsif ($stmt eq "SSLProtocol" ) {
print NSS "## we ignore the arguments to SSLProtocol. The original value was:\n";
print NSS "##$_";
print NSS "## The following is a _range_ from TLSv1.0 to TLSv1.2.\n";
print NSS "## You may also specify SSLv3 at the beginning of the range. Not done here:\n";
print NSS "NSSProtocol TLSv1.0,TLSv1.2\n\n";
next;
} elsif ($stmt eq "SSLCACertificatePath") {
$SSLCACertificatePath = $value;
$comment = 1;
} elsif ($stmt eq "SSLCACertificateFile") {
$SSLCACertificateFile = $value;
$comment = 1;
} elsif ($stmt eq "SSLCertificateFile") {
print NSS "NSSCertificateDatabase $NSSDir\n";
print NSS "NSSNickName Server-Cert\n";
$SSLCertificateFile = $value;
$comment = 1;
} elsif ($stmt eq "SSLCertificateKeyFile") {
$SSLCertificateKeyFile = $value;
$comment = 1;
} elsif ($stmt eq "SSLCARevocationPath") {
$SSLCARevocationPath = $value;
$comment = 1;
} elsif ($stmt eq "SSLCARevocationFile") {
$SSLCARevocationFile = $value;
$comment = 1;
} elsif ($stmt eq "SSLPassPhraseDialog") {
print NSS "NSSPassPhraseHelper /usr/sbin/nss_pcache\n";
$passphrase = 1;
$comment = 1;
}
if (exists($skip{$stmt})) {
print NSS "# Skipping, not applicable in mod_nss\n";
print NSS "##$_";
next;
}
# Fix up any remaining directive names
s/SSL/NSS/;
if (exists($insert{$stmt})) {
print NSS "$_";
print NSS $insert{$stmt};
next;
}
# Fall-through to print whatever is left
if ($comment) {
print NSS "##$_";
$comment = 0;
} else {
print NSS $_;
}
}
if ($passphrase == 0) {
print NSS "NSSPassPhraseHelper /usr/sbin/nss_pcache\n";
}
close(NSS);
close(SSL);
#
# Create NSS certificate database and import any existing certificates
#
if ($opt{c}) {
print STDERR "Creating NSS certificate database.\n";
run_command("certutil -N -d $NSSDir");
# Convert the certificate into pkcs12 format
if ($SSLCertificateFile ne "" && $SSLCertificateKeyFile ne "") {
my $subject = get_cert_subject($SSLCertificateFile);
print STDERR "Importing certificate $subject as \"Server-Cert\".\n";
run_command("openssl pkcs12 -export -in $SSLCertificateFile -inkey $SSLCertificateKeyFile -out server.p12 -name \"Server-Cert\" -passout pass:foo ");
run_command("pk12util -i server.p12 -d $NSSDir -W foo ");
}
if ($SSLCACertificateFile ne "") {
my $subject = get_cert_subject($SSLCACertificateFile);
if ($subject ne "") {
print STDERR "Importing CA certificate $subject\n";
run_command("certutil -A -n \"$subject\" -t \"CT,,\" -d $NSSDir -a -i $SSLCACertificateFile ");
}
}
if ($SSLCACertificatePath ne "") {
opendir(DIR, $SSLCACertificatePath) or die "can't opendir $SSLCACertificatePath: $!";
while (defined($file = readdir(DIR))) {
next if -d $file;
# we can operate directly on the hash files so don't have to worry
# about any SKIPME's.
if ($file =~ /hash.*/) {
my $subject = get_cert_subject("$SSLCACertificatePath/$file");
if ($subject ne "") {
print STDERR "Importing CA certificate $subject\n";
run_command("certutil -A -n \"$subject\" -t \"CT,,\" -d $NSSDir -a -i $SSLCACertificatePath/$file ");
}
}
}
closedir(DIR);
}
if ($SSLCARevocationFile ne "") {
print STDERR "Importing CRL file $CARevocationFile\n";
# Convert to DER format
run_command("openssl crl -in $SSLCARevocationFile -out /root/crl.tmp -inform PEM -outform DER");
run_command("crlutil -I -t 1 -d $NSSDir -i /root/crl.tmp");
unlink("/root/crl.tmp");
}
if ($SSLCARevocationPath ne "") {
opendir(DIR, $SSLCARevocationPath) or die "can't opendir $SSLCARevocationPath: $!";
while (defined($file = readdir(DIR))) {
next if -d $file;
# we can operate directly on the hash files so don't have to worry
# about any SKIPME's.
if ($file =~ /hash.*/) {
my $subject = get_cert_subject("$SSLCARevocationPath/$file");
if ($subject ne "") {
print STDERR "Importing CRL file $file\n";
# Convert to DER format
run_command("openssl crl -in $SSLCARevocationPath/$file -out /root/crl.tmp -inform PEM -outform DER");
run_command("crlutil -I -t 1 -d $NSSDir -i /root/crl.tmp");
unlink("/root/crl.tmp");
}
}
}
closedir(DIR);
}
}
print STDERR "\n\nConversion complete.\n";
print STDERR "The output file should contain a valid mod_nss configuration based on\n";
print STDERR "the mod_ssl directives from the input file.\n";
print STDERR "Recommended directory: /etc/apache2/mod_nss.d , suffix .conf!\n";
print STDERR "Also make sure to edit /etc/apache2/conf.d/mod_nss.conf and to remove the\n";
print STDERR "<VirtualHost> section if you do not need it.\n\n";
print STDERR "Also, do not forget to rename the ssl based apache config file";
print STDERR "(our example: myhost-ssl.conf) to a file that does not end in .conf\n";
print STDERR "(our example: myhost-ssl.conf-disabled-for-nss)\n\n";
print STDERR "Then, restart apache (rcapache2 restart) and have a look into the error logs.\n";
exit(0);
# Migrate configuration from OpenSSL to NSS
sub get_ciphers {
my $str = shift;
%cipher_list = (
"rc4" => ":ALL:SSLv2:RSA:MD5:MEDIUM:RC4:",
"rc4export" => ":ALL:SSLv2:RSA:EXP:EXPORT40:MD5:RC4:",
"rc2" => ":ALL:SSLv2:RSA:MD5:MEDIUM:RC2:",
"rc2export" => ":ALL:SSLv2:RSA:EXP:EXPORT40:MD5:RC2:",
"des" => ":ALL:SSLv2:RSA:EXP:EXPORT56:MD5:DES:LOW:",
"desede3" => ":ALL:SSLv2:RSA:MD5:3DES:HIGH:",
"rsa_rc4_128_md5" => ":ALL:SSLv3:TLSv1:RSA:MD5:RC4:MEDIUM:",
"rsa_rc4_128_sha" => ":ALL:SSLv3:TLSv1:RSA:SHA:RC4:MEDIUM:",
"rsa_3des_sha" => ":ALL:SSLv3:TLSv1:RSA:SHA:3DES:HIGH:",
"rsa_des_sha" => ":ALL:SSLv3:TLSv1:RSA:SHA:DES:LOW:",
"rsa_rc4_40_md5" => ":ALL:SSLv3:TLSv1:RSA:EXP:EXPORT40:RC4:",
"rsa_rc2_40_md5" => ":ALL:SSLv3:TLSv1:RSA:EXP:EXPORT40:RC2:",
"rsa_null_md5" => ":SSLv3:TLSv1:RSA:MD5:NULL:",
"rsa_null_sha" => ":SSLv3:TLSv1:RSA:SHA:NULL:",
"rsa_des_56_sha" => ":ALL:SSLv3:TLSv1:RSA:DES:SHA:EXP:EXPORT56:",
"rsa_rc4_56_sha" => ":ALL:SSLv3:TLSv1:RSA:RC4:SHA:EXP:EXPORT56:",
);
$NUM_CIPHERS = 16;
for ($i = 0; $i < $NUM_CIPHERS; $i++) {
$selected[$i] = 0;
}
# Don't need to worry about the ordering properties of "+" because
# NSS always chooses the "best" cipher anyway. You can't specify
# preferred order.
# -1: this cipher is completely out
# 0: this cipher is currently unselected, but maybe added later
# 1: this cipher is selected
@s = split(/:/, $str);
for ($i = 0; $i <= $#s; $i++) {
$j = 0;
$val = 1;
# ! means this cipher is disabled forever
if ($s[$i] =~ /^!/) {
$val = -1;
($s[$i] =~ s/^!//);
} elsif ($s[$i] =~ /^-/) {
$val = 0;
($s[$i] =~ s/^-//);
} elsif ($s[$i] =~ /^+/) {
($s[$i] =~ s/^+//);
}
for $cipher (sort keys %cipher_list) {
$match = 0;
# For embedded + we do an AND for all options
if ($s[$i] =~ m/(\w+\+)+/) {
@sub = split(/^\+/, $s[$i]);
$match = 1;
for ($k = 0; $k <=$#sub; $k++) {
if ($cipher_list{$cipher} !=~ m/:$sub[$k]:/) {
$match = 0;
}
}
} else { # straightforward match
if ($cipher_list{$cipher} =~ m/:$s[$i]:/) {
$match = 1;
}
}
if ($match && $selected[$j] != -1) {
$selected[$j] = $val;
}
$j++;
}
}
# NSS doesn't honor the order of a cipher list, it uses the "strongest"
# cipher available. So we'll print out the ciphers as SSLv2, SSLv3 and
# the NSS ciphers not available in OpenSSL.
$str = "SSLv2:SSLv3";
@s = split(/:/, $str);
$ciphersuite = "";
for ($i = 0; $i <= $#s; $i++) {
$j = 0;
for $cipher (sort keys %cipher_list) {
if ($cipher_list{$cipher} =~ m/:$s[$i]:/) {
if ($selected[$j]) {
$ciphersuite .= "+";
} else {
$ciphersuite .= "-";
}
$ciphersuite .= $cipher . ",";
}
$j++;
}
}
$ciphersuite .= "-fortezza,-fortezza_rc4_128_sha,-fortezza_null,-fips_des_sha,+fips_3des_sha,-rsa_aes_128_sha,-rsa_aes_256_sha";
return $ciphersuite;
}
# Given the filename of a PEM file, use openssl to fetch the certificate
# subject
sub get_cert_subject {
my $file = shift;
my $subject = "";
return "" if ! -T $file;
$subject = `openssl x509 -subject < $file | head -1`;
$subject =~ s/subject= \///; # Remove leading subject= \
$subject =~ s/\//,/g; # Replace / with , as separator
$subject =~ s/Email=.*(,){0,1}//; # Remove Email attribute
$subject =~ s/,$//; # Remove any trailing commas
chomp($subject);
return $subject;
}
#
# Wrapper around the system() command
sub run_command {
my @args = shift;
my $status = 0;
$status = 0xffff & system(@args);
return if ($status == 0);
print STDERR "Command '@args' failed: $!\n";
exit;
}