NAME
Crypt::OpenSSL::CA::Test - Testing Crypt::OpenSSL::CA
SYNOPSIS
use Crypt::OpenSSL::CA::Test qw(:default %test_der_DNs);
use Test::Group;
my $utf8 = Crypt::OpenSSL::CA::Test->test_simple_utf8();
run_perl_ok(<<"SCRIPT");
use Crypt::OpenSSL::CA::Test;
warn "Hello world";
SCRIPT
skip_next_test "Devel::Leak needed" if cannot_check_SV_leaks;
test "leaky code" => sub {
leaks_SVs_ok {
# Do stuff
}, -max => 6;
};
skip_next_test "Memchmark needed" if cannot_check_bytes_leaks;
test "even leakier code" => sub {
leaks_bytes_ok {
# Do stuff
}, -max => 51200;
};
use Crypt::OpenSSL::CA::Test qw(x509_decoder);
my $dn_as_tree = x509_decoder('Name')->decode($dn_der);
DESCRIPTION
This module provides some handy utility functions for testing Crypt::OpenSSL::CA. "leaks_bytes_ok" and "leaks_SVs_ok" are especially handy for testing XS or Inline::C stuff.
EXPORTED FUNCTIONS
All functions described in this section factor some useful test tactics and are exported by default. The "SAMPLE INPUTS" may also be exported upon request.
- fork_and_do($sub)
-
Runs $sub in a forked process, and returns the PID it runs under. The child process calls $sub in void context, and terminates when $sub does so; if $sub terminates normally, the exit code of the child process will be 0, otherwise it will be 1. The child process will not perform global destruction, even if $sub contains an explicit call to "exit" in perlfunc.
- openssl_path
-
Returns the path to the
opensslcommand-line tool, if it is known, or undef. Useful for skipping tests that depend on "run_thru_openssl" being able to run. - run_thru_openssl($stdin_text, $arg1, $arg2, ...)
-
Runs the command
openssl $arg1 $arg2 ..., feeding it $stdin_text on its standard input. In list context, returns a ($stdout_text, $stderr_text) pair. In scalar context, returns the text of the combined standard output and error streams. Throws an exception if theopensslcommand is unavailable (that is, "openssl_path" returns undef). Upon return $? will be set to the exit status ofopenssl. - run_dumpasn1($der)
-
Runs the dumpasn1 command (found in $ENV{PATH}) on $der and returns its output. Throws an exception if dumpasn1 fails for some reason.
- run_perl($scripttext)
-
Runs $scripttext in a sub-Perl interpreter, returning the text of its combined stdout and stderr as a single string. $? is set to the exit value of same.
- run_perl_ok($scripttext)
- run_perl_ok($scripttext, \$stdout)
- run_perl_ok($scripttext, \$stdout, $testname)
-
Like "run_perl" but simultaneously asserts (using Test::More) that the exit value is successful. The return value of the sub is the status of the assertion; the output of $scripttext (that is, the return value of the underlying call to run_perl) is transmitted to the caller by modifying in-place the scalar reference passed as the second argument, if any. Additionally the aforementioned output is passed to "diag" in Test::More if the script does exit with nonzero status.
- errstack_empty_ok()
-
Asserts that OpenSSL's error stack is empty, and clears it if not. To be run at the end of every test.
- cannot_check_SV_leaks()
-
Returns true iff Devel::Leak is unavailable.
- cannot_check_bytes_leaks()
-
Returns true iff Memchmark is unavailable.
- leaks_SVs_ok($coderef, %named_arguments)
-
Executes $coderef and asserts (with Test::More) that it doesn't leak Perl SVs (checked using Devel::Leak). As a tester, you should arrange for $coderef to manipulate about 10 SVs; smaller leaks will not be detected (see -max below).
Available named arguments are:
- -name => $testname
-
The name of the test, as in the second argument to "ok" in Test::Builder.
- -max => $threshold
-
The minimum number of leaked SVs to look for. The default is 6. Setting this too low will trigger false positives, as Devel::Leak needs a couple of SVs of its own.
- leaks_bytes_ok($coderef)
- leaks_bytes_ok($coderef, $testname)
-
Executes $coderef and asserts (with Test::More) that it doesn't leak memory (checked using Memchmark). As a tester, you should arrange for $coderef to manipulate about 100k of memory; smaller leaks will not be detected (see -max below).
Available named arguments are:
- -name => $testname
-
The name of the test, as in the second argument to "ok" in Test::Builder.
- -max => $threshold
-
The minimum number of leaked bytes to look for. The default is 51200. Setting this too low will trigger false positives, as Memchmark needs to allocate some memory of its own.
- certificate_looks_ok($pem_certificate)
- certificate_looks_ok($pem_certificate, $test_name)
-
Checks that a certificate passed as a PEM string looks OK to OpenSSL, meaning that the signature validates OK and OpenSSL is able to parse it.
- certificate_chain_ok($pem_certificate, \@certchain )
- certificate_chain_ok($pem_certificate, \@certchain , $test_name)
-
Checks that a certificate passed as a PEM string is validly signed by the certificate chain @certchain, which is a list of PEM strings passed as a reference.
- certificate_chain_invalid_ok($pem_certificate, \@certchain )
-
The converse of "certificate_chain_ok"; checks that $pem_certificate is not validly signed by @certchain. Note, however, that there is a case where both certificate_chain_ok and certificate_chain_invalid_ok both fail, and that is when @certchain doesn't contain any valid CA certificate.
- x509_schema()
-
Returns the ASN.1 schema for the whole X509 specification, as a string that Convert::ASN1 will grok.
- x509_decoder($name)
-
Returns the same as "find" in Convert::ASN1 would when called upon an object that would previously have "x509_schema" fed to him. The difference is that x509_decoder checks for errors and will therefore never return undef.
The returned object has a
->decodeobject that serves to validate the various pieces of DER produced by OpenSSL from within the tests.
SAMPLE INPUTS
Crypt::OpenSSL::CA::Test also provides a couple of constants and class methods to serve as inputs for tests. All such symbols are exportable, but not exported by default (see "SYNOPSIS") and they start with test_, so as to be clearly identified as sample data in the test code.
- test_simple_utf8()
- test_bmp_utf8()
-
Two constant functions that return test strings for testing the UTF-8 capabilities of Crypt::OpenSSL::CA. Both strings are encoded internally in UTF-8 in the sense of "is_utf8" in utf8. test_simple_utf8() contains only characters in the Latin1 range; test_bmp_utf8() contains only characters outside Latin1, but inside the Basic Multilingual Plane.
- %test_der_DNs
-
Contains a set of DER-encoded DNs. The keys are the DNs in "RFC4514" in Crypt::OpenSSL::CA::Resources notation, and the values are strings of bytes. Available DN keys for now are
CN=Zoinx,C=fr. - @test_DN_CAs
-
The DN used in all CA and self-signed certificates, namely "%test_self_signed_certs", "%test_rootca_certs" and friends. Set in the same order as the parameters to the new function in "Crypt::OpenSSL::CA::X509_NAME" in Crypt::OpenSSL::CA.
- %test_reqs_SPKAC
-
Certificate signing requests (CSRs) in Netscape "SPKAC" in Crypt::OpenSSL::CA::AlphabetSoup format, as if generated by
openssl spkac -key test.key -challenge secretbut without the trailing newline, and with the leading
SPKAC=removed. - %test_reqs_PKCS10
-
Certificate signing requests (CSRs) in standard PKCS#10 PEM format, as if generated by
openssl req -new -key test.key -batchbut without the trailing newline, and with the leading
SPKAC=removed. - %test_keys_plaintext
-
An array of test private keys in PEM format. The values of this hash tables are strings in PEM format (that is, Base64-encoded DER with delimiters
-----BEGIN RSA PRIVATE KEY-----and-----END RSA PRIVATE KEY-----, without encryption). The keys are well-known key handles that are re-used throughout the sample input hashes below:- rsa1024
- rsa2048
-
RSA keys of size 1024 bits and 2048 bits respectively.
More RSA keys can be obtained using the command
openssl genrsa 1024or similar (e.g. changing the key size)
- %test_keys_password
-
The same private keys as in "%test_keys_plaintext", but protected with
secretas the password. Keys are the same as in %test_keys_plaintext; values are encrypted using 3DES-CBC, as if by the commandopenssl rsa -des3 -passout pass:secret -in test.key - %test_public_keys
-
Public keys obtained from the "%test_keys_plaintext" using the following
opensslcommand:openssl rsa -pubout -in test.key - %test_self_signed_certs
-
Self-signed certificates obtained from the "%test_keys_plaintext" as if using the following
opensslcommand:openssl req -x509 -new -key test.key -batch -days 10958 \ -extensions usr_certwhere 10958 stands for a validity period of 30 years, so that these self-signed certificates seldom actually expire. Because the default configuration is used, the world-famous yet Belgian Internet Widgits Pty Ltd company is put in charge as issuer and subject of these certificates.
- %test_rootca_certs
-
Self-signed certificates just like "%test_self_signed_certs", except that these certificates are signed using
-extensions v3_cain lieu of-extensions usr_cert, resulting in certificates that have theCABasicConstraint set totrue. Those certificates can therefore be used e.g. in the second argument to "certificate_chain_ok", unlike "%test_self_signed_certs" which, lacking a CA BasicConstraint, usually cannot be a non-leaf part of a valid certification chain as per RFC3280 section 6.1.4, item k. - %test_entity_certs
-
Certificates generated using
openssl cafrom "%test_rootca_certs", "%test_keys_plaintext" and the default OpenSSL configuration using the procedure described in "Building a toy CA:" in Crypt::OpenSSL::CA::Resources where the preciseopensslcommands used areopenssl req -new -batch -subj "/C=fr/O=Yoyodyne/CN=John Doe" \ -key test.key | \ openssl ca -batch -days 10958 -in /dev/stdinIn particular this means that entries keyed off the same identifier in %test_entity_certs and %test_rootca_certs form a valid RFC3280 certification path: that is,
certificate_chain_ok($test_entity_certs{$id}, [ $test_rootca_certs{$id} ]); # Worksholds for every valid $id. But conversely,
certificate_chain_ok($test_entity_certs{$id}, [ $test_self_signed_certs{$id} ]); # NOT OK!fails, due to the lack of a
CA:TRUEBasicConstraint extension in %test_self_signed_certs.Notice that in the sample inputs, CAs and end entities share the same set of private RSA keys "%test_keys_plaintext" which would not be the case in a real PKI deployment. However this is of little impact, if any, on the test coverage of Crypt::OpenSSL::CA as we never make use of the fact that all certificates for a given key length actually have the same private key.
INTERNAL METHODS
- _tempdir
-
Returns a temporary directory e.g. for storing the
ca-bundle.crtfor "certificate_chain_ok". - _unique_number
-
As the name implies. Typically used to create unique filenames in "_tempdir".
TODO
Maybe "leaks_bytes_ok" and "leaks_SVs_ok" deserve a CPAN module of their own?