Apache-Test
view release on metacpan or search on metacpan
lib/Apache/TestSSLCA.pm view on Meta::CPAN
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
package Apache::TestSSLCA;
use strict;
use warnings FATAL => 'all';
use Cwd ();
use DirHandle ();
use File::Path ();
use File::Copy 'cp';
use File::Basename;
use File::Spec::Functions qw(devnull);
use Apache::TestConfig ();
use Apache::TestTrace;
use constant SSLCA_DB => 'index.txt';
use vars qw(@EXPORT_OK &import);
use subs qw(symlink);
@EXPORT_OK = qw(dn dn_vars dn_oneline);
*import = \&Exporter::import;
my $openssl = $ENV{APACHE_TEST_OPENSSL_CMD} || 'openssl';
my $version = version();
my $CA = 'asf';
my $Config; #global Apache::TestConfig object
my $days = '-days 365';
my $cakey = 'keys/ca.pem';
my $cacert = 'certs/ca.crt';
my $capolicy = '-policy policy_anything';
my $cacrl = 'crl/ca-bundle.crl';
my $dgst = 'sha256';
#we use the same password for everything
my $pass = 'httpd';
my $passin = "-passin pass:$pass";
my $passout = "-passout pass:$pass";
# (limited) subjectAltName otherName testing
my $san_msupn = ', otherName:msUPN;UTF8:$mail';
my $san_dnssrv = ', otherName:1.3.6.1.5.5.7.8.7;IA5:_https.$CN';
# in 0.9.7 s/Email/emailAddress/ in DN
my $email_field = Apache::Test::normalize_vstring($version) <
Apache::Test::normalize_vstring("0.9.7") ?
"Email" : "emailAddress";
# downgrade to SHA-1 for OpenSSL before 0.9.8
if (Apache::Test::normalize_vstring($version) <
Apache::Test::normalize_vstring("0.9.8")) {
$dgst = 'sha1';
# otherNames in x509v3_config are not supported either
$san_msupn = $san_dnssrv = "";
}
my $sslproto = "all";
eval { require Net::SSLeay; };
if (Apache::Test::normalize_vstring($version) >=
Apache::Test::normalize_vstring("1.1.1")
&& !defined(&Net::SSLeay::CTX_set_post_handshake_auth)) {
# OpenSSL 1.1.1 disables PHA by default client-side in TLSv1.3 but
# most clients are not updated to enable it (at time of writing).
# Many mod_ssl tests require working PHA, so disable v1.3 unless
# using an updated Net::SSLeay. This is strictly insufficient
# since an updated IO::Socket::SSL is also needed; to be
# continued. Ref: https://github.com/openssl/openssl/issues/6933
$sslproto = "all -TLSv1.3";
}
my $ca_dn = {
asf => {
C => 'US',
ST => 'California',
L => 'San Francisco',
O => 'ASF',
OU => 'httpd-test',
CN => '',
$email_field => 'test-dev@httpd.apache.org',
},
};
my $cert_dn = {
client_snakeoil => {
C => 'AU',
ST => 'Queensland',
L => 'Mackay',
O => 'Snake Oil, Ltd.',
OU => 'Staff',
},
client_ok => {
},
client_colon => {
CN => "user:colon",
lib/Apache/TestSSLCA.pm view on Meta::CPAN
for my $k (@parts) {
next unless $dn->{$k};
if ($rfc2253) {
my $tmp = $dn->{$k};
$tmp =~ s{([,+"\\<>;])}{\\$1}g;
$tmp =~ s{^([ #])}{\\$1};
$tmp =~ s{ $}{\\ };
$string .= "," if $string;
$string .= "$k=$tmp";
}
else {
$string .= "/$k=$dn->{$k}";
}
}
$string;
}
sub openssl {
return $openssl unless @_;
my $cmd = "$openssl @_";
info $cmd;
unless (system($cmd) == 0) {
my $status = $? >> 8;
die "system @_ failed (exit status=$status)";
}
}
my @dirs = qw(keys newcerts certs crl export csr conf proxy);
sub init {
for my $dir (@dirs) {
gendir($dir);
}
}
sub config_file {
my $name = shift;
my $file = "conf/$name.cnf";
return $file if -e $file;
my $dn = dn($name);
my $db = SSLCA_DB;
writefile($db, '', 1) unless -e $db;
writefile($file, <<EOF);
mail = $dn->{$email_field}
CN = $dn->{CN}
[ req ]
distinguished_name = req_distinguished_name
attributes = req_attributes
prompt = no
default_bits = 2048
output_password = $pass
[ req_distinguished_name ]
C = $dn->{C}
ST = $dn->{ST}
L = $dn->{L}
O = $dn->{O}
OU = $dn->{OU}
CN = \$CN
$email_field = \$mail
[ req_attributes ]
challengePassword = $pass
[ ca ]
default_ca = CA_default
[ CA_default ]
certs = certs # Where the issued certs are kept
new_certs_dir = newcerts # default place for new certs.
crl_dir = crl # Where the issued crl are kept
database = $db # database index file.
serial = serial # The current serial number
certificate = $cacert # The CA certificate
crl = $cacrl # The current CRL
private_key = $cakey # The private key
default_days = 365 # how long to certify for
default_crl_days = 365 # how long before next CRL
default_md = $dgst # which md to use.
preserve = no # keep passed DN ordering
[ policy_anything ]
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
$email_field = optional
[ client_ok_ext ]
nsComment = This Is A Comment
1.3.6.1.4.1.18060.12.0 = DER:0c064c656d6f6e73
subjectAltName = email:\$mail$san_msupn
[ server_ext ]
subjectAltName = DNS:\$CN$san_dnssrv
EOF
return $file;
}
sub config {
my $name = shift;
my $file = config_file($name);
my $config = "-config $file";
$config;
}
use constant PASSWORD_CLEARTEXT =>
Apache::TestConfig::WIN32 || Apache::TestConfig::NETWARE;
#http://www.modssl.org/docs/2.8/ssl_reference.html#ToC21
my $basic_auth_password =
PASSWORD_CLEARTEXT ? 'password': 'xxj31ZMTZzkVA';
my $digest_auth_hash = '$1$OXLyS...$Owx8s2/m9/gfkcRVXzgoE/';
sub new_ca {
writefile('serial', "01\n", 1);
writefile('ssl.htpasswd',
join ':', dn_oneline('client_snakeoil'),
$basic_auth_password);
openssl req => "-new -x509 -keyout $cakey -out $cacert $days",
config('ca');
export_cert('ca'); #useful for importing into IE
}
sub new_key {
my $name = shift;
my $encrypt = @_ ? "@_ $passout" : "";
my $out = "-out keys/$name.pem $encrypt";
if ($name =~ /dsa/) {
#this takes a long time so just do it once
#don't do this in real life
unless (-e 'dsa-param') {
openssl dsaparam => '-inform PEM -out dsa-param 2048';
}
openssl gendsa => "$out dsa-param";
}
else {
openssl genrsa => "$out 2048";
}
}
sub new_cert {
my $name = shift;
openssl req => "-new -key keys/$name.pem -out csr/$name.csr",
$passin, $passout, config($name);
sign_cert($name);
export_cert($name);
}
sub sign_cert {
my $name = shift;
my $exts = '';
$exts = ' -extensions client_ok_ext' if $name =~ /client_ok/;
$exts = ' -extensions server_ext' if $name =~ /server/;
openssl ca => "$capolicy -in csr/$name.csr -out certs/$name.crt",
$passin, config($name), '-batch', $exts;
}
#handy for importing into a browser such as netscape
sub export_cert {
my $name = shift;
return if $name =~ /^server/; #no point in exporting server certs
openssl pkcs12 => "-export -in certs/$name.crt -inkey keys/$name.pem",
"-out export/$name.p12", $passin, $passout;
}
( run in 1.485 second using v1.01-cache-2.11-cpan-39bf76dae61 )