164 lines
5.8 KiB
Perl
164 lines
5.8 KiB
Perl
#! /usr/bin/env perl
|
|
# Copyright 2018-2021 The OpenSSL Project Authors. All Rights Reserved.
|
|
#
|
|
# Licensed under the Apache License 2.0 (the "License"). You may not use
|
|
# this file except in compliance with the License. You can obtain a copy
|
|
# in the file LICENSE in the source distribution or at
|
|
# https://www.openssl.org/source/license.html
|
|
|
|
use strict;
|
|
no strict 'refs'; # To be able to use strings as function refs
|
|
use OpenSSL::Test;
|
|
use OpenSSL::Test::Utils;
|
|
use Errno qw(:POSIX);
|
|
use POSIX qw(:limits_h strerror);
|
|
|
|
use Data::Dumper;
|
|
|
|
setup('test_errstr');
|
|
|
|
# In a cross compiled situation, there are chances that our
|
|
# application is linked against different C libraries than
|
|
# perl, and may thereby get different error messages for the
|
|
# same error.
|
|
# The safest is not to test under such circumstances.
|
|
plan skip_all => 'This is unsupported for cross compiled configurations'
|
|
if config('CROSS_COMPILE');
|
|
|
|
# The same can be said when compiling OpenSSL with mingw configuration
|
|
# on Windows when built with msys perl. Similar problems are also observed
|
|
# in MSVC builds, depending on the perl implementation used.
|
|
plan skip_all => 'This is unsupported on MSYS/MinGW or MSWin32'
|
|
if $^O eq 'msys' or $^O eq 'MSWin32';
|
|
|
|
plan skip_all => 'OpenSSL is configured "no-autoerrinit" or "no-err"'
|
|
if disabled('autoerrinit') || disabled('err');
|
|
|
|
# OpenSSL constants found in <openssl/err.h>
|
|
use constant ERR_SYSTEM_FLAG => INT_MAX + 1;
|
|
use constant ERR_LIB_OFFSET => 23; # Offset of the "library" errcode section
|
|
|
|
# OpenSSL "library" numbers
|
|
use constant ERR_LIB_NONE => 1;
|
|
|
|
# We use Errno::EXPORT_OK as a list of known errno values on the current
|
|
# system. libcrypto's ERR should either use the same string as perl, or if
|
|
# it was outside the range that ERR looks at, ERR gives the reason string
|
|
# "reason(nnn)", where nnn is the errno number.
|
|
|
|
plan tests => scalar @Errno::EXPORT_OK
|
|
+1 # Checking that error 128 gives 'reason(128)'
|
|
+1 # Checking that error 0 gives the library name
|
|
+1; # Check trailing whitespace is removed.
|
|
|
|
# Test::More:ok() has a sub prototype, which means we need to use the '&ok'
|
|
# syntax to force it to accept a list as a series of arguments.
|
|
|
|
foreach my $errname (@Errno::EXPORT_OK) {
|
|
# The error names are perl constants, which are implemented as functions
|
|
# returning the numeric value of that name.
|
|
my $errcode = "Errno::$errname"->();
|
|
|
|
SKIP: {
|
|
# On most systems, there is no E macro for errcode zero in <errno.h>,
|
|
# which means that it seldom comes up here. However, reports indicate
|
|
# that some platforms do have an E macro for errcode zero.
|
|
# With perl, errcode zero is a bit special. Perl consistently gives
|
|
# the empty string for that one, while the C strerror() may give back
|
|
# something else. The easiest way to deal with that possible mismatch
|
|
# is to skip this errcode.
|
|
skip "perl error strings and ssystem error strings for errcode 0 differ", 1
|
|
if $errcode == 0;
|
|
# On some systems (for example Hurd), there are negative error codes.
|
|
# These are currently unsupported in OpenSSL error reports.
|
|
skip "negative error codes are not supported in OpenSSL", 1
|
|
if $errcode < 0;
|
|
|
|
&ok(match_syserr_reason($errcode));
|
|
}
|
|
}
|
|
|
|
# OpenSSL library 1 is the "unknown" library
|
|
&ok(match_opensslerr_reason(ERR_LIB_NONE << ERR_LIB_OFFSET | 256,
|
|
"reason(256)"));
|
|
# Reason code 0 of any library gives the library name as reason
|
|
&ok(match_opensslerr_reason(ERR_LIB_NONE << ERR_LIB_OFFSET | 0,
|
|
"unknown library"));
|
|
&ok(match_any("Trailing whitespace \n\t", "?", ( "Trailing whitespace" )));
|
|
|
|
exit 0;
|
|
|
|
# For an error string "error:xxxxxxxx:lib:func:reason", this returns
|
|
# the following array:
|
|
#
|
|
# ( "xxxxxxxx", "lib", "func", "reason" )
|
|
sub split_error {
|
|
# Limit to 5 items, in case the reason contains a colon
|
|
my @erritems = split /:/, $_[0], 5;
|
|
|
|
# Remove the first item, which is always "error"
|
|
shift @erritems;
|
|
|
|
return @erritems;
|
|
}
|
|
|
|
# Compares the first argument as string to each of the arguments 3 and on,
|
|
# and returns an array of two elements:
|
|
# 0: True if the first argument matched any of the others, otherwise false
|
|
# 1: A string describing the test
|
|
# The returned array can be used as the arguments to Test::More::ok()
|
|
sub match_any {
|
|
my $first = shift;
|
|
my $desc = shift;
|
|
my @strings = @_;
|
|
|
|
# ignore trailing whitespace
|
|
$first =~ s/\s+$//;
|
|
|
|
if (scalar @strings > 1) {
|
|
$desc = "match '$first' ($desc) with one of ( '"
|
|
. join("', '", @strings) . "' )";
|
|
} else {
|
|
$desc = "match '$first' ($desc) with '$strings[0]'";
|
|
}
|
|
|
|
return ( scalar(
|
|
grep { ref $_ eq 'Regexp' ? $first =~ $_ : $first eq $_ }
|
|
@strings
|
|
) > 0,
|
|
$desc );
|
|
}
|
|
|
|
sub match_opensslerr_reason {
|
|
my $errcode = shift;
|
|
my @strings = @_;
|
|
|
|
my $errcode_hex = sprintf "%x", $errcode;
|
|
my $reason =
|
|
( run(app([ qw(openssl errstr), $errcode_hex ]), capture => 1) )[0];
|
|
$reason =~ s|\R$||;
|
|
$reason = ( split_error($reason) )[3];
|
|
|
|
return match_any($reason, $errcode_hex, @strings);
|
|
}
|
|
|
|
sub match_syserr_reason {
|
|
my $errcode = shift;
|
|
|
|
my @strings = ();
|
|
# The POSIX reason string
|
|
push @strings, eval {
|
|
# Set $! to the error number...
|
|
local $! = $errcode;
|
|
# ... and $! will give you the error string back
|
|
$!
|
|
};
|
|
# Occasionally, we get an error code that is simply not translatable
|
|
# to POSIX semantics on VMS, and we get an error string saying so.
|
|
push @strings, qr/^non-translatable vms error code:/ if $^O eq 'VMS';
|
|
# The OpenSSL fallback string
|
|
push @strings, "reason($errcode)";
|
|
|
|
return match_opensslerr_reason(ERR_SYSTEM_FLAG | $errcode, @strings);
|
|
}
|