Merge pull request #1830 from Jakuje/fuzz

Introduce unit tests and address more oss-fuzz issues  (mostly ASN1 parser)
This commit is contained in:
Frank Morgner 2020-01-17 15:15:20 +01:00 committed by GitHub
commit 5c55546685
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
42 changed files with 1771 additions and 58 deletions

3
.gitignore vendored
View File

@ -115,5 +115,8 @@ src/tests/p11test/p11test
tests/*.log
tests/*.trs
src/tests/unittests/*.log
src/tests/unittests/*.trs
src/tests/unittests/asn1
version.m4.ci

View File

@ -283,7 +283,7 @@ script:
fi
- if [ "${DO_SIMULATION}" = "cac" ]; then
cd $TRAVIS_BUILD_DIR;
make check && sudo make install;
make check && sudo make install || (cat tests/*log && exit);
export LD_LIBRARY_PATH=/usr/local/lib;
cd src/tests/p11test/;
./p11test -s 0 -p 12345678 -i &

View File

@ -28,6 +28,10 @@ dist_noinst_DATA = README \
packaging/debian.templates/rules
dist_doc_DATA = NEWS
include $(top_srcdir)/aminclude_static.am
clean-local: code-coverage-clean
distclean-local: code-coverage-dist-clean
Generate-ChangeLog:
rm -f ChangeLog.tmp "$(srcdir)/ChangeLog"
test -n "$(GIT)"

View File

@ -131,6 +131,8 @@ case "${host}" in
;;
esac
AX_CODE_COVERAGE()
AX_CHECK_COMPILE_FLAG([-Wunknown-warning-option], [have_unknown_warning_option="yes"], [have_unknown_warning_option="no"], [-Werror])
AM_CONDITIONAL([HAVE_UNKNOWN_WARNING_OPTION], [test "${have_unknown_warning_option}" = "yes"])
@ -1098,6 +1100,7 @@ AC_CONFIG_FILES([
src/tests/regression/Makefile
src/tests/p11test/Makefile
src/tests/fuzzing/Makefile
src/tests/unittests/Makefile
src/tools/Makefile
src/tools/versioninfo-tools.rc
src/tools/versioninfo-opensc-notify.rc
@ -1160,6 +1163,7 @@ SM default module: ${DEFAULT_SM_MODULE}
SM default path: $(eval eval eval echo "${DEFAULT_SM_MODULE_PATH}")
DNIe UI support: ${enable_dnie_ui}
Notification support: ${enable_notify}
Code coverage: ${enable_code_coverage}
PC/SC default provider: ${DEFAULT_PCSC_PROVIDER}
PKCS11 default provider: $(eval eval eval echo "${DEFAULT_PKCS11_PROVIDER}")

View File

@ -0,0 +1,32 @@
# ===========================================================================
# https://www.gnu.org/software/autoconf-archive/ax_ac_append_to_file.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_AC_APPEND_TO_FILE([FILE],[DATA])
#
# DESCRIPTION
#
# Appends the specified data to the specified Autoconf is run. If you want
# to append to a file when configure is run use AX_APPEND_TO_FILE instead.
#
# LICENSE
#
# Copyright (c) 2009 Allan Caffee <allan.caffee@gmail.com>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 10
AC_DEFUN([AX_AC_APPEND_TO_FILE],[
AC_REQUIRE([AX_FILE_ESCAPES])
m4_esyscmd(
AX_FILE_ESCAPES
[
printf "%s" "$2" >> "$1"
])
])

32
m4/ax_ac_print_to_file.m4 Normal file
View File

@ -0,0 +1,32 @@
# ===========================================================================
# https://www.gnu.org/software/autoconf-archive/ax_ac_print_to_file.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_AC_PRINT_TO_FILE([FILE],[DATA])
#
# DESCRIPTION
#
# Writes the specified data to the specified file when Autoconf is run. If
# you want to print to a file when configure is run use AX_PRINT_TO_FILE
# instead.
#
# LICENSE
#
# Copyright (c) 2009 Allan Caffee <allan.caffee@gmail.com>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 10
AC_DEFUN([AX_AC_PRINT_TO_FILE],[
m4_esyscmd(
AC_REQUIRE([AX_FILE_ESCAPES])
[
printf "%s" "$2" > "$1"
])
])

View File

@ -0,0 +1,28 @@
# ===========================================================================
# https://www.gnu.org/software/autoconf-archive/ax_add_am_macro_static.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_ADD_AM_MACRO_STATIC([RULE])
#
# DESCRIPTION
#
# Adds the specified rule to $AMINCLUDE.
#
# LICENSE
#
# Copyright (c) 2009 Tom Howard <tomhoward@users.sf.net>
# Copyright (c) 2009 Allan Caffee <allan.caffee@gmail.com>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 8
AC_DEFUN([AX_ADD_AM_MACRO_STATIC],[
AC_REQUIRE([AX_AM_MACROS_STATIC])
AX_AC_APPEND_TO_FILE(AMINCLUDE_STATIC,[$1])
])

38
m4/ax_am_macros_static.m4 Normal file
View File

@ -0,0 +1,38 @@
# ===========================================================================
# https://www.gnu.org/software/autoconf-archive/ax_am_macros_static.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_AM_MACROS_STATIC
#
# DESCRIPTION
#
# Adds support for macros that create Automake rules. You must manually
# add the following line
#
# include $(top_srcdir)/aminclude_static.am
#
# to your Makefile.am files.
#
# LICENSE
#
# Copyright (c) 2009 Tom Howard <tomhoward@users.sf.net>
# Copyright (c) 2009 Allan Caffee <allan.caffee@gmail.com>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 11
AC_DEFUN([AMINCLUDE_STATIC],[aminclude_static.am])
AC_DEFUN([AX_AM_MACROS_STATIC],
[
AX_AC_PRINT_TO_FILE(AMINCLUDE_STATIC,[
# ]AMINCLUDE_STATIC[ generated automatically by Autoconf
# from AX_AM_MACROS_STATIC on ]m4_esyscmd([LC_ALL=C date])[
])
])

95
m4/ax_check_gnu_make.m4 Normal file
View File

@ -0,0 +1,95 @@
# ===========================================================================
# https://www.gnu.org/software/autoconf-archive/ax_check_gnu_make.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_CHECK_GNU_MAKE([run-if-true],[run-if-false])
#
# DESCRIPTION
#
# This macro searches for a GNU version of make. If a match is found:
#
# * The makefile variable `ifGNUmake' is set to the empty string, otherwise
# it is set to "#". This is useful for including a special features in a
# Makefile, which cannot be handled by other versions of make.
# * The makefile variable `ifnGNUmake' is set to #, otherwise
# it is set to the empty string. This is useful for including a special
# features in a Makefile, which can be handled
# by other versions of make or to specify else like clause.
# * The variable `_cv_gnu_make_command` is set to the command to invoke
# GNU make if it exists, the empty string otherwise.
# * The variable `ax_cv_gnu_make_command` is set to the command to invoke
# GNU make by copying `_cv_gnu_make_command`, otherwise it is unset.
# * If GNU Make is found, its version is extracted from the output of
# `make --version` as the last field of a record of space-separated
# columns and saved into the variable `ax_check_gnu_make_version`.
# * Additionally if GNU Make is found, run shell code run-if-true
# else run shell code run-if-false.
#
# Here is an example of its use:
#
# Makefile.in might contain:
#
# # A failsafe way of putting a dependency rule into a makefile
# $(DEPEND):
# $(CC) -MM $(srcdir)/*.c > $(DEPEND)
#
# @ifGNUmake@ ifeq ($(DEPEND),$(wildcard $(DEPEND)))
# @ifGNUmake@ include $(DEPEND)
# @ifGNUmake@ else
# fallback code
# @ifGNUmake@ endif
#
# Then configure.in would normally contain:
#
# AX_CHECK_GNU_MAKE()
# AC_OUTPUT(Makefile)
#
# Then perhaps to cause gnu make to override any other make, we could do
# something like this (note that GNU make always looks for GNUmakefile
# first):
#
# if ! test x$_cv_gnu_make_command = x ; then
# mv Makefile GNUmakefile
# echo .DEFAULT: > Makefile ;
# echo \ $_cv_gnu_make_command \$@ >> Makefile;
# fi
#
# Then, if any (well almost any) other make is called, and GNU make also
# exists, then the other make wraps the GNU make.
#
# LICENSE
#
# Copyright (c) 2008 John Darrington <j.darrington@elvis.murdoch.edu.au>
# Copyright (c) 2015 Enrico M. Crisostomo <enrico.m.crisostomo@gmail.com>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 12
AC_DEFUN([AX_CHECK_GNU_MAKE],dnl
[AC_PROG_AWK
AC_CACHE_CHECK([for GNU make],[_cv_gnu_make_command],[dnl
_cv_gnu_make_command="" ;
dnl Search all the common names for GNU make
for a in "$MAKE" make gmake gnumake ; do
if test -z "$a" ; then continue ; fi ;
if "$a" --version 2> /dev/null | grep GNU 2>&1 > /dev/null ; then
_cv_gnu_make_command=$a ;
AX_CHECK_GNU_MAKE_HEADLINE=$("$a" --version 2> /dev/null | grep "GNU Make")
ax_check_gnu_make_version=$(echo ${AX_CHECK_GNU_MAKE_HEADLINE} | ${AWK} -F " " '{ print $(NF); }')
break ;
fi
done ;])
dnl If there was a GNU version, then set @ifGNUmake@ to the empty string, '#' otherwise
AS_VAR_IF([_cv_gnu_make_command], [""], [AS_VAR_SET([ifGNUmake], ["#"])], [AS_VAR_SET([ifGNUmake], [""])])
AS_VAR_IF([_cv_gnu_make_command], [""], [AS_VAR_SET([ifnGNUmake], [""])], [AS_VAR_SET([ifnGNUmake], ["#"])])
AS_VAR_IF([_cv_gnu_make_command], [""], [AS_UNSET(ax_cv_gnu_make_command)], [AS_VAR_SET([ax_cv_gnu_make_command], [${_cv_gnu_make_command}])])
AS_VAR_IF([_cv_gnu_make_command], [""],[$2],[$1])
AC_SUBST([ifGNUmake])
AC_SUBST([ifnGNUmake])
])

272
m4/ax_code_coverage.m4 Normal file
View File

@ -0,0 +1,272 @@
# ===========================================================================
# https://www.gnu.org/software/autoconf-archive/ax_code_coverage.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_CODE_COVERAGE()
#
# DESCRIPTION
#
# Defines CODE_COVERAGE_CPPFLAGS, CODE_COVERAGE_CFLAGS,
# CODE_COVERAGE_CXXFLAGS and CODE_COVERAGE_LIBS which should be included
# in the CPPFLAGS, CFLAGS CXXFLAGS and LIBS/LIBADD variables of every
# build target (program or library) which should be built with code
# coverage support. Also add rules using AX_ADD_AM_MACRO_STATIC; and
# $enable_code_coverage which can be used in subsequent configure output.
# CODE_COVERAGE_ENABLED is defined and substituted, and corresponds to the
# value of the --enable-code-coverage option, which defaults to being
# disabled.
#
# Test also for gcov program and create GCOV variable that could be
# substituted.
#
# Note that all optimization flags in CFLAGS must be disabled when code
# coverage is enabled.
#
# Usage example:
#
# configure.ac:
#
# AX_CODE_COVERAGE
#
# Makefile.am:
#
# include $(top_srcdir)/aminclude_static.am
#
# my_program_LIBS = ... $(CODE_COVERAGE_LIBS) ...
# my_program_CPPFLAGS = ... $(CODE_COVERAGE_CPPFLAGS) ...
# my_program_CFLAGS = ... $(CODE_COVERAGE_CFLAGS) ...
# my_program_CXXFLAGS = ... $(CODE_COVERAGE_CXXFLAGS) ...
#
# clean-local: code-coverage-clean
# distclean-local: code-coverage-dist-clean
#
# This results in a "check-code-coverage" rule being added to any
# Makefile.am which do "include $(top_srcdir)/aminclude_static.am"
# (assuming the module has been configured with --enable-code-coverage).
# Running `make check-code-coverage` in that directory will run the
# module's test suite (`make check`) and build a code coverage report
# detailing the code which was touched, then print the URI for the report.
#
# This code was derived from Makefile.decl in GLib, originally licensed
# under LGPLv2.1+.
#
# LICENSE
#
# Copyright (c) 2012, 2016 Philip Withnall
# Copyright (c) 2012 Xan Lopez
# Copyright (c) 2012 Christian Persch
# Copyright (c) 2012 Paolo Borelli
# Copyright (c) 2012 Dan Winship
# Copyright (c) 2015,2018 Bastien ROUCARIES
#
# This library is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or (at
# your option) any later version.
#
# This library is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
# General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#serial 32
m4_define(_AX_CODE_COVERAGE_RULES,[
AX_ADD_AM_MACRO_STATIC([
# Code coverage
#
# Optional:
# - CODE_COVERAGE_DIRECTORY: Top-level directory for code coverage reporting.
# Multiple directories may be specified, separated by whitespace.
# (Default: \$(top_builddir))
# - CODE_COVERAGE_OUTPUT_FILE: Filename and path for the .info file generated
# by lcov for code coverage. (Default:
# \$(PACKAGE_NAME)-\$(PACKAGE_VERSION)-coverage.info)
# - CODE_COVERAGE_OUTPUT_DIRECTORY: Directory for generated code coverage
# reports to be created. (Default:
# \$(PACKAGE_NAME)-\$(PACKAGE_VERSION)-coverage)
# - CODE_COVERAGE_BRANCH_COVERAGE: Set to 1 to enforce branch coverage,
# set to 0 to disable it and leave empty to stay with the default.
# (Default: empty)
# - CODE_COVERAGE_LCOV_SHOPTS_DEFAULT: Extra options shared between both lcov
# instances. (Default: based on $CODE_COVERAGE_BRANCH_COVERAGE)
# - CODE_COVERAGE_LCOV_SHOPTS: Extra options to shared between both lcov
# instances. (Default: $CODE_COVERAGE_LCOV_SHOPTS_DEFAULT)
# - CODE_COVERAGE_LCOV_OPTIONS_GCOVPATH: --gcov-tool pathtogcov
# - CODE_COVERAGE_LCOV_OPTIONS_DEFAULT: Extra options to pass to the
# collecting lcov instance. (Default: $CODE_COVERAGE_LCOV_OPTIONS_GCOVPATH)
# - CODE_COVERAGE_LCOV_OPTIONS: Extra options to pass to the collecting lcov
# instance. (Default: $CODE_COVERAGE_LCOV_OPTIONS_DEFAULT)
# - CODE_COVERAGE_LCOV_RMOPTS_DEFAULT: Extra options to pass to the filtering
# lcov instance. (Default: empty)
# - CODE_COVERAGE_LCOV_RMOPTS: Extra options to pass to the filtering lcov
# instance. (Default: $CODE_COVERAGE_LCOV_RMOPTS_DEFAULT)
# - CODE_COVERAGE_GENHTML_OPTIONS_DEFAULT: Extra options to pass to the
# genhtml instance. (Default: based on $CODE_COVERAGE_BRANCH_COVERAGE)
# - CODE_COVERAGE_GENHTML_OPTIONS: Extra options to pass to the genhtml
# instance. (Default: $CODE_COVERAGE_GENHTML_OPTIONS_DEFAULT)
# - CODE_COVERAGE_IGNORE_PATTERN: Extra glob pattern of files to ignore
#
# The generated report will be titled using the \$(PACKAGE_NAME) and
# \$(PACKAGE_VERSION). In order to add the current git hash to the title,
# use the git-version-gen script, available online.
# Optional variables
# run only on top dir
if CODE_COVERAGE_ENABLED
ifeq (\$(abs_builddir), \$(abs_top_builddir))
CODE_COVERAGE_DIRECTORY ?= \$(top_builddir)
CODE_COVERAGE_OUTPUT_FILE ?= \$(PACKAGE_NAME)-\$(PACKAGE_VERSION)-coverage.info
CODE_COVERAGE_OUTPUT_DIRECTORY ?= \$(PACKAGE_NAME)-\$(PACKAGE_VERSION)-coverage
CODE_COVERAGE_BRANCH_COVERAGE ?=
CODE_COVERAGE_LCOV_SHOPTS_DEFAULT ?= \$(if \$(CODE_COVERAGE_BRANCH_COVERAGE),\
--rc lcov_branch_coverage=\$(CODE_COVERAGE_BRANCH_COVERAGE))
CODE_COVERAGE_LCOV_SHOPTS ?= \$(CODE_COVERAGE_LCOV_SHOPTS_DEFAULT)
CODE_COVERAGE_LCOV_OPTIONS_GCOVPATH ?= --gcov-tool \"\$(GCOV)\"
CODE_COVERAGE_LCOV_OPTIONS_DEFAULT ?= \$(CODE_COVERAGE_LCOV_OPTIONS_GCOVPATH)
CODE_COVERAGE_LCOV_OPTIONS ?= \$(CODE_COVERAGE_LCOV_OPTIONS_DEFAULT)
CODE_COVERAGE_LCOV_RMOPTS_DEFAULT ?=
CODE_COVERAGE_LCOV_RMOPTS ?= \$(CODE_COVERAGE_LCOV_RMOPTS_DEFAULT)
CODE_COVERAGE_GENHTML_OPTIONS_DEFAULT ?=\
\$(if \$(CODE_COVERAGE_BRANCH_COVERAGE),\
--rc genhtml_branch_coverage=\$(CODE_COVERAGE_BRANCH_COVERAGE))
CODE_COVERAGE_GENHTML_OPTIONS ?= \$(CODE_COVERAGE_GENHTML_OPTIONS_DEFAULT)
CODE_COVERAGE_IGNORE_PATTERN ?=
GITIGNOREFILES = \$(GITIGNOREFILES) \$(CODE_COVERAGE_OUTPUT_FILE) \$(CODE_COVERAGE_OUTPUT_DIRECTORY)
code_coverage_v_lcov_cap = \$(code_coverage_v_lcov_cap_\$(V))
code_coverage_v_lcov_cap_ = \$(code_coverage_v_lcov_cap_\$(AM_DEFAULT_VERBOSITY))
code_coverage_v_lcov_cap_0 = @echo \" LCOV --capture\" \$(CODE_COVERAGE_OUTPUT_FILE);
code_coverage_v_lcov_ign = \$(code_coverage_v_lcov_ign_\$(V))
code_coverage_v_lcov_ign_ = \$(code_coverage_v_lcov_ign_\$(AM_DEFAULT_VERBOSITY))
code_coverage_v_lcov_ign_0 = @echo \" LCOV --remove /tmp/*\" \$(CODE_COVERAGE_IGNORE_PATTERN);
code_coverage_v_genhtml = \$(code_coverage_v_genhtml_\$(V))
code_coverage_v_genhtml_ = \$(code_coverage_v_genhtml_\$(AM_DEFAULT_VERBOSITY))
code_coverage_v_genhtml_0 = @echo \" GEN \" \"\$(CODE_COVERAGE_OUTPUT_DIRECTORY)\";
code_coverage_quiet = \$(code_coverage_quiet_\$(V))
code_coverage_quiet_ = \$(code_coverage_quiet_\$(AM_DEFAULT_VERBOSITY))
code_coverage_quiet_0 = --quiet
# sanitizes the test-name: replaces with underscores: dashes and dots
code_coverage_sanitize = \$(subst -,_,\$(subst .,_,\$(1)))
# Use recursive makes in order to ignore errors during check
check-code-coverage:
-\$(AM_V_at)\$(MAKE) \$(AM_MAKEFLAGS) -k check
\$(AM_V_at)\$(MAKE) \$(AM_MAKEFLAGS) code-coverage-capture
# Capture code coverage data
code-coverage-capture: code-coverage-capture-hook
\$(code_coverage_v_lcov_cap)\$(LCOV) \$(code_coverage_quiet) \$(addprefix --directory ,\$(CODE_COVERAGE_DIRECTORY)) --capture --output-file \"\$(CODE_COVERAGE_OUTPUT_FILE).tmp\" --test-name \"\$(call code_coverage_sanitize,\$(PACKAGE_NAME)-\$(PACKAGE_VERSION))\" --no-checksum --compat-libtool \$(CODE_COVERAGE_LCOV_SHOPTS) \$(CODE_COVERAGE_LCOV_OPTIONS)
\$(code_coverage_v_lcov_ign)\$(LCOV) \$(code_coverage_quiet) \$(addprefix --directory ,\$(CODE_COVERAGE_DIRECTORY)) --remove \"\$(CODE_COVERAGE_OUTPUT_FILE).tmp\" \"/tmp/*\" \$(CODE_COVERAGE_IGNORE_PATTERN) --output-file \"\$(CODE_COVERAGE_OUTPUT_FILE)\" \$(CODE_COVERAGE_LCOV_SHOPTS) \$(CODE_COVERAGE_LCOV_RMOPTS)
-@rm -f \"\$(CODE_COVERAGE_OUTPUT_FILE).tmp\"
\$(code_coverage_v_genhtml)LANG=C \$(GENHTML) \$(code_coverage_quiet) \$(addprefix --prefix ,\$(CODE_COVERAGE_DIRECTORY)) --output-directory \"\$(CODE_COVERAGE_OUTPUT_DIRECTORY)\" --title \"\$(PACKAGE_NAME)-\$(PACKAGE_VERSION) Code Coverage\" --legend --show-details \"\$(CODE_COVERAGE_OUTPUT_FILE)\" \$(CODE_COVERAGE_GENHTML_OPTIONS)
@echo \"file://\$(abs_builddir)/\$(CODE_COVERAGE_OUTPUT_DIRECTORY)/index.html\"
code-coverage-clean:
-\$(LCOV) --directory \$(top_builddir) -z
-rm -rf \"\$(CODE_COVERAGE_OUTPUT_FILE)\" \"\$(CODE_COVERAGE_OUTPUT_FILE).tmp\" \"\$(CODE_COVERAGE_OUTPUT_DIRECTORY)\"
-find . \\( -name \"*.gcda\" -o -name \"*.gcno\" -o -name \"*.gcov\" \\) -delete
code-coverage-dist-clean:
A][M_DISTCHECK_CONFIGURE_FLAGS = \$(A][M_DISTCHECK_CONFIGURE_FLAGS) --disable-code-coverage
else # ifneq (\$(abs_builddir), \$(abs_top_builddir))
check-code-coverage:
code-coverage-capture: code-coverage-capture-hook
code-coverage-clean:
code-coverage-dist-clean:
endif # ifeq (\$(abs_builddir), \$(abs_top_builddir))
else #! CODE_COVERAGE_ENABLED
# Use recursive makes in order to ignore errors during check
check-code-coverage:
@echo \"Need to reconfigure with --enable-code-coverage\"
# Capture code coverage data
code-coverage-capture: code-coverage-capture-hook
@echo \"Need to reconfigure with --enable-code-coverage\"
code-coverage-clean:
code-coverage-dist-clean:
endif #CODE_COVERAGE_ENABLED
# Hook rule executed before code-coverage-capture, overridable by the user
code-coverage-capture-hook:
.PHONY: check-code-coverage code-coverage-capture code-coverage-dist-clean code-coverage-clean code-coverage-capture-hook
])
])
AC_DEFUN([_AX_CODE_COVERAGE_ENABLED],[
AX_CHECK_GNU_MAKE([],[AC_MSG_ERROR([not using GNU make that is needed for coverage])])
AC_REQUIRE([AX_ADD_AM_MACRO_STATIC])
# check for gcov
AC_CHECK_TOOL([GCOV],
[$_AX_CODE_COVERAGE_GCOV_PROG_WITH],
[:])
AS_IF([test "X$GCOV" = "X:"],
[AC_MSG_ERROR([gcov is needed to do coverage])])
AC_SUBST([GCOV])
dnl Check if gcc is being used
AS_IF([ test "$GCC" = "no" ], [
AC_MSG_ERROR([not compiling with gcc, which is required for gcov code coverage])
])
AC_CHECK_PROG([LCOV], [lcov], [lcov])
AC_CHECK_PROG([GENHTML], [genhtml], [genhtml])
AS_IF([ test x"$LCOV" = x ], [
AC_MSG_ERROR([To enable code coverage reporting you must have lcov installed])
])
AS_IF([ test x"$GENHTML" = x ], [
AC_MSG_ERROR([Could not find genhtml from the lcov package])
])
dnl Build the code coverage flags
dnl Define CODE_COVERAGE_LDFLAGS for backwards compatibility
CODE_COVERAGE_CPPFLAGS="-DNDEBUG"
CODE_COVERAGE_CFLAGS="-O0 -g -fprofile-arcs -ftest-coverage"
CODE_COVERAGE_CXXFLAGS="-O0 -g -fprofile-arcs -ftest-coverage"
CODE_COVERAGE_LIBS="-lgcov"
AC_SUBST([CODE_COVERAGE_CPPFLAGS])
AC_SUBST([CODE_COVERAGE_CFLAGS])
AC_SUBST([CODE_COVERAGE_CXXFLAGS])
AC_SUBST([CODE_COVERAGE_LIBS])
])
AC_DEFUN([AX_CODE_COVERAGE],[
dnl Check for --enable-code-coverage
# allow to override gcov location
AC_ARG_WITH([gcov],
[AS_HELP_STRING([--with-gcov[=GCOV]], [use given GCOV for coverage (GCOV=gcov).])],
[_AX_CODE_COVERAGE_GCOV_PROG_WITH=$with_gcov],
[_AX_CODE_COVERAGE_GCOV_PROG_WITH=gcov])
AC_MSG_CHECKING([whether to build with code coverage support])
AC_ARG_ENABLE([code-coverage],
AS_HELP_STRING([--enable-code-coverage],
[Whether to enable code coverage support]),,
enable_code_coverage=no)
AM_CONDITIONAL([CODE_COVERAGE_ENABLED], [test "x$enable_code_coverage" = xyes])
AC_SUBST([CODE_COVERAGE_ENABLED], [$enable_code_coverage])
AC_MSG_RESULT($enable_code_coverage)
AS_IF([ test "x$enable_code_coverage" = xyes ], [
_AX_CODE_COVERAGE_ENABLED
])
_AX_CODE_COVERAGE_RULES
])

30
m4/ax_file_escapes.m4 Normal file
View File

@ -0,0 +1,30 @@
# ===========================================================================
# https://www.gnu.org/software/autoconf-archive/ax_file_escapes.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_FILE_ESCAPES
#
# DESCRIPTION
#
# Writes the specified data to the specified file.
#
# LICENSE
#
# Copyright (c) 2008 Tom Howard <tomhoward@users.sf.net>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 8
AC_DEFUN([AX_FILE_ESCAPES],[
AX_DOLLAR="\$"
AX_SRB="\\135"
AX_SLB="\\133"
AX_BS="\\\\"
AX_DQ="\""
])

View File

@ -577,6 +577,13 @@ static int decode_bit_string(const u8 * inbuf, size_t inlen, void *outbuf,
if (inlen < 1)
return SC_ERROR_INVALID_ASN1_OBJECT;
/* 8.6.2.3 If the bitstring is empty, there shall be no subsequent octets,
* and the initial octet shall be zero. */
if (inlen == 1 && *in != 0)
return SC_ERROR_INVALID_ASN1_OBJECT;
/* ITU-T Rec. X.690 8.6.2.2: The number shall be in the range zero to seven. */
if ((*in & ~0x07) != 0)
return SC_ERROR_INVALID_ASN1_OBJECT;
memset(outbuf, 0, outlen);
zero_bits = *in & 0x07;
in++;
@ -591,9 +598,13 @@ static int decode_bit_string(const u8 * inbuf, size_t inlen, void *outbuf,
int bits_to_go;
*out = 0;
if (octets_left == 1)
if (octets_left == 1 && zero_bits > 0) {
bits_to_go = 8 - zero_bits;
else
/* Verify the padding is zero bits */
if (*in & (1 << (zero_bits-1))) {
return SC_ERROR_INVALID_ASN1_OBJECT;
}
} else
bits_to_go = 8;
if (invert)
for (i = 0; i < bits_to_go; i++) {
@ -706,17 +717,28 @@ static int encode_bit_field(const u8 *inbuf, size_t inlen,
return encode_bit_string(data, bits, outbuf, outlen, 1);
}
int sc_asn1_decode_integer(const u8 * inbuf, size_t inlen, int *out)
int sc_asn1_decode_integer(const u8 * inbuf, size_t inlen, int *out, int strict)
{
int a = 0, is_negative = 0;
size_t i = 0;
if (inlen > sizeof(int) || inlen == 0)
if (inlen == 0) {
return SC_ERROR_INVALID_ASN1_OBJECT;
}
if (inlen > sizeof(int)) {
return SC_ERROR_NOT_SUPPORTED;
}
if (inbuf[0] & 0x80) {
if (strict && inlen > 1 && inbuf[0] == 0xff && (inbuf[1] & 0x80)) {
return SC_ERROR_INVALID_ASN1_OBJECT;
}
is_negative = 1;
a |= 0xff^(*inbuf++);
i = 1;
} else {
if (strict && inlen > 1 && inbuf[0] == 0x00 && (inbuf[1] & 0x80) == 0) {
return SC_ERROR_INVALID_ASN1_OBJECT;
}
}
for (; i < inlen; i++) {
if (a > (INT_MAX >> 8) || a < (INT_MIN + (1<<8))) {
@ -797,7 +819,8 @@ static int asn1_encode_integer(int in, u8 ** obj, size_t * objsize)
int
sc_asn1_decode_object_id(const u8 *inbuf, size_t inlen, struct sc_object_id *id)
{
int a;
int large_second_octet = 0;
unsigned int a = 0;
const u8 *p = inbuf;
int *octet;
@ -807,18 +830,36 @@ sc_asn1_decode_object_id(const u8 *inbuf, size_t inlen, struct sc_object_id *id)
sc_init_oid(id);
octet = id->value;
a = *p;
*octet++ = a / 40;
*octet++ = a % 40;
inlen--;
/* The first octet can be 0, 1 or 2 and is derived from the first byte */
a = MIN(*p / 40, 2);
*octet++ = a;
/* The second octet fits here if the previous was 0 or 1 and second one is smaller than 40.
* for the value 2 we can go up to 47. Otherwise the first bit needs to be set
* and we continue reading further */
if ((*p & 0x80) == 0) {
*octet++ = *p - (a * 40);
inlen--;
} else {
large_second_octet = 1;
}
while (inlen) {
p++;
if (!large_second_octet)
p++;
/* This signalizes empty most significant bits, which means
* the unsigned integer encoding is not minimal */
if (*p == 0x80) {
sc_init_oid(id);
return SC_ERROR_INVALID_ASN1_OBJECT;
}
/* Use unsigned type here so we can process the whole INT range.
* Values can not be negative */
a = *p & 0x7F;
inlen--;
while (inlen && *p & 0x80) {
/* Limit the OID values to int size and do not overflow */
if (a > (INT_MAX>>7)) {
if (a > (UINT_MAX>>7)) {
sc_init_oid(id);
return SC_ERROR_NOT_SUPPORTED;
}
@ -827,12 +868,26 @@ sc_asn1_decode_object_id(const u8 *inbuf, size_t inlen, struct sc_object_id *id)
a |= *p & 0x7F;
inlen--;
}
if (*p & 0x80) {
/* We dropped out from previous cycle on the end of
* data while still expecting continuation of value */
sc_init_oid(id);
return SC_ERROR_INVALID_ASN1_OBJECT;
}
if (large_second_octet) {
a -= (2 * 40);
}
if (a > INT_MAX) {
sc_init_oid(id);
return SC_ERROR_NOT_SUPPORTED;
}
*octet++ = a;
if (octet - id->value >= SC_MAX_OBJECT_ID_OCTETS) {
sc_init_oid(id);
return SC_ERROR_INVALID_ASN1_OBJECT;
}
};
large_second_octet = 0;
}
return 0;
}
@ -864,10 +919,13 @@ sc_asn1_encode_object_id(u8 **buf, size_t *buflen, const struct sc_object_id *id
*p = k * 40;
break;
case 1:
if (k > 39)
if (k > 39 && id->value[0] < 2) {
return SC_ERROR_INVALID_ARGUMENTS;
*p++ += k;
break;
}
/* We can encode larger IDs to multiple bytes
* similarly as the following IDs */
k += *p;
/* fall through */
default:
shift = 28;
while (shift && (k >> shift) == 0)
@ -1448,7 +1506,7 @@ static int asn1_decode_entry(sc_context_t *ctx,struct sc_asn1_entry *entry,
case SC_ASN1_INTEGER:
case SC_ASN1_ENUMERATED:
if (parm != NULL) {
r = sc_asn1_decode_integer(obj, objlen, (int *) entry->parm);
r = sc_asn1_decode_integer(obj, objlen, (int *) entry->parm, 1);
sc_debug(ctx, SC_LOG_DEBUG_ASN1, "%*.*sdecoding '%s' returned %d\n", depth, depth, "",
entry->name, *((int *) entry->parm));
}

View File

@ -100,7 +100,7 @@ int sc_asn1_decode_bit_string(const u8 * inbuf, size_t inlen,
/* non-inverting version */
int sc_asn1_decode_bit_string_ni(const u8 * inbuf, size_t inlen,
void *outbuf, size_t outlen);
int sc_asn1_decode_integer(const u8 * inbuf, size_t inlen, int *out);
int sc_asn1_decode_integer(const u8 * inbuf, size_t inlen, int *out, int strict);
int sc_asn1_decode_object_id(const u8 * inbuf, size_t inlen,
struct sc_object_id *id);
int sc_asn1_encode_object_id(u8 **buf, size_t *buflen,

View File

@ -78,7 +78,7 @@ static int cac_cac1_get_certificate(sc_card_t *card, u8 **out_buf, size_t *out_l
out_ptr = *out_buf ? *out_buf : buf;
sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, CAC_INS_GET_CERTIFICATE, 0, 0 );
len = MIN(left, 100);
for (; left > 0;) { /* Increments for readability in the end of the function */
while (left > 0) {
apdu.resp = out_ptr;
apdu.le = len;
apdu.resplen = left;

View File

@ -1101,6 +1101,8 @@ static int coolkey_read_object(sc_card_t *card, unsigned long object_id, size_t
size_t len;
int r;
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
ulong2bebytes(&params.object_id[0], object_id);
out_ptr = out_buf;
@ -1127,7 +1129,7 @@ static int coolkey_read_object(sc_card_t *card, unsigned long object_id, size_t
return out_len;
fail:
return r;
LOG_FUNC_RETURN(card->ctx, r);
}
/*
@ -1208,7 +1210,7 @@ static int coolkey_read_binary(sc_card_t *card, unsigned int idx,
r = coolkey_read_object(card, priv->obj->id, 0, data, priv->obj->length,
priv->nonce, sizeof(priv->nonce));
priv->nonce, sizeof(priv->nonce));
if (r < 0)
goto done;
@ -1367,6 +1369,8 @@ coolkey_fill_object(sc_card_t *card, sc_cardctl_coolkey_object_t *obj)
sc_cardctl_coolkey_object_t *obj_entry;
coolkey_private_data_t * priv = COOLKEY_DATA(card);
LOG_FUNC_CALLED(card->ctx);
if (obj->data != NULL) {
return SC_SUCCESS;
}
@ -1378,7 +1382,7 @@ coolkey_fill_object(sc_card_t *card, sc_cardctl_coolkey_object_t *obj)
priv->nonce, sizeof(priv->nonce));
if (r != (int)buf_len) {
free(new_obj_data);
return SC_ERROR_CORRUPTED_DATA;
LOG_FUNC_RETURN(card->ctx, SC_ERROR_CORRUPTED_DATA);
}
obj_entry = coolkey_find_object_by_id(&priv->objects_list, obj->id);
if (obj_entry == NULL) {
@ -1397,7 +1401,7 @@ coolkey_fill_object(sc_card_t *card, sc_cardctl_coolkey_object_t *obj)
}
obj_entry->data = new_obj_data;
obj->data = new_obj_data;
return SC_SUCCESS;
LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
}
/*
@ -1419,6 +1423,8 @@ coolkey_find_attribute(sc_card_t *card, sc_cardctl_coolkey_attribute_t *attribut
attribute->attribute_length = 0;
attribute->attribute_value = NULL;
LOG_FUNC_CALLED(card->ctx);
if (obj == NULL) {
/* cast away const so we can cache the data value */
int r = coolkey_fill_object(card, (sc_cardctl_coolkey_object_t *)attribute->object);
@ -1444,7 +1450,6 @@ coolkey_find_attribute(sc_card_t *card, sc_cardctl_coolkey_attribute_t *attribut
return SC_ERROR_CORRUPTED_DATA;
}
/*
* now loop through all the attributes in the list. first find the start of the list
*/
@ -1460,7 +1465,7 @@ coolkey_find_attribute(sc_card_t *card, sc_cardctl_coolkey_attribute_t *attribut
size_t record_len = coolkey_get_attribute_record_len(attr, object_record_type, buf_len);
/* make sure we have the complete record */
if (buf_len < record_len || record_len < 4) {
return SC_ERROR_CORRUPTED_DATA;
return SC_ERROR_CORRUPTED_DATA;
}
/* does the attribute match the one we are looking for */
if (attr_type == coolkey_get_attribute_type(attr, object_record_type, record_len)) {
@ -1477,7 +1482,7 @@ coolkey_find_attribute(sc_card_t *card, sc_cardctl_coolkey_attribute_t *attribut
return coolkey_get_attribute_data_fixed(attr_type, fixed_attributes, attribute);
}
return SC_ERROR_DATA_OBJECT_NOT_FOUND;
LOG_FUNC_RETURN(card->ctx, SC_ERROR_DATA_OBJECT_NOT_FOUND);
}
/*
@ -2078,6 +2083,7 @@ coolkey_process_combined_object(sc_card_t *card, coolkey_private_data_t *priv, u
object_offset += current_object_len;
/* record this object */
sc_log(card->ctx, "Add new object id=%ld", object_id);
r = coolkey_add_object(priv, object_id, current_object, current_object_len, 1);
if (r) {
goto done;
@ -2171,7 +2177,7 @@ static int coolkey_initialize(sc_card_t *card)
break;
}
r = coolkey_read_object(card, COOLKEY_COMBINED_OBJECT_ID, 0, object, object_len,
priv->nonce, sizeof(priv->nonce));
priv->nonce, sizeof(priv->nonce));
if (r < 0) {
free(object);
break;
@ -2183,6 +2189,7 @@ static int coolkey_initialize(sc_card_t *card)
}
combined_processed = 1;
} else {
sc_log(card->ctx, "Add new object id=%ld, len=%u", object_id, object_len);
r = coolkey_add_object(priv, object_id, NULL, object_len, 0);
if (r != SC_SUCCESS)
sc_log(card->ctx, "coolkey_add_object() returned %d", r);
@ -2216,19 +2223,19 @@ static int coolkey_initialize(sc_card_t *card)
coolkey_make_cuid_from_cplc(&priv->cuid, &cplc_data);
priv->token_name = (u8 *)strdup("COOLKEY");
if (priv->token_name == NULL) {
r= SC_ERROR_OUT_OF_MEMORY;
r = SC_ERROR_OUT_OF_MEMORY;
goto cleanup;
}
priv->token_name_length = sizeof("COOLKEY")-1;
}
card->drv_data = priv;
return SC_SUCCESS;
LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
cleanup:
if (priv) {
coolkey_free_private_data(priv);
}
return r;
LOG_FUNC_RETURN(card->ctx, r);
}

View File

@ -32,8 +32,15 @@
extern "C" {
#endif
#ifdef _MSC_VER
#define PACKED
#pragma pack(push,1)
#elif defined(__GNUC__)
#define PACKED __attribute__ ((__packed__))
#endif
/* returned by the iso get status apdu with the global platform cplc data parameters */
typedef struct global_platform_cplc_data {
typedef struct global_platform_cplc_data {
u8 tag[2];
u8 length;
u8 ic_fabricator[2];
@ -54,13 +61,20 @@ typedef struct global_platform_cplc_data {
u8 ic_personalizaer[2];
u8 ic_personalization_data[2];
u8 ic_personalization_id[4];
} global_platform_cplc_data_t;
} PACKED global_platform_cplc_data_t;
int gp_select_aid(struct sc_card *card, const struct sc_aid *aid);
int gp_select_card_manager(struct sc_card *card);
int gp_select_isd_rid(struct sc_card *card);
int gp_get_cplc_data(struct sc_card *card, global_platform_cplc_data_t *cplc_data);
#ifdef _MSC_VER
#undef PACKED
#pragma pack(pop)
#elif defined(__GNUC__)
#undef PACKED
#endif
#ifdef __cplusplus
}
#endif

View File

@ -358,7 +358,7 @@ iso7816_process_fci(struct sc_card *card, struct sc_file *file,
/* fall through */
case 0x80:
/* determine the file size */
if (sc_asn1_decode_integer(p, length, &size) == 0 && size >= 0) {
if (sc_asn1_decode_integer(p, length, &size, 0) == 0 && size >= 0) {
file->size = size;
sc_log(ctx, " bytes in file: %"SC_FORMAT_LEN_SIZE_T"u",
file->size);

View File

@ -538,6 +538,7 @@ static int sc_pkcs15emu_coolkey_init(sc_pkcs15_card_t *p15card)
r = (card->ops->card_ctl)(card, SC_CARDCTL_COOLKEY_INIT_GET_OBJECTS, &count);
LOG_TEST_RET(card->ctx, r, "Can not initiate objects.");
sc_log(card->ctx, "Iterating over %d objects", count);
for (i = 0; i < count; i++) {
struct sc_cardctl_coolkey_object coolkey_obj;
struct sc_pkcs15_object obj_obj;
@ -555,7 +556,7 @@ static int sc_pkcs15emu_coolkey_init(sc_pkcs15_card_t *p15card)
if (r < 0)
LOG_FUNC_RETURN(card->ctx, r);
sc_log(card->ctx, "Loading object %d", i);
memset(&obj_obj, 0, sizeof(obj_obj));
/* coolkey applets have label only on the certificates,
* but we should copy it also to the keys matching the same ID */
@ -571,6 +572,7 @@ static int sc_pkcs15emu_coolkey_init(sc_pkcs15_card_t *p15card)
}
switch (obj_class) {
case CKO_PRIVATE_KEY:
sc_log(card->ctx, "Processing private key object %d", i);
r = coolkey_get_attribute_ulong(card, &coolkey_obj, CKA_KEY_TYPE, &key_type);
/* default to CKK_RSA */
if (r == SC_ERROR_DATA_OBJECT_NOT_FOUND) {
@ -593,12 +595,12 @@ static int sc_pkcs15emu_coolkey_init(sc_pkcs15_card_t *p15card)
if (key_type == CKK_RSA) {
obj_type = SC_PKCS15_TYPE_PRKEY_RSA;
if (key) {
prkey_info.modulus_length = key->u.rsa.modulus.len*8;
prkey_info.modulus_length = key->u.rsa.modulus.len*8;
}
} else if (key_type == CKK_EC) {
obj_type = SC_PKCS15_TYPE_PRKEY_EC;
if (key) {
prkey_info.field_length = key->u.ec.params.field_length;
prkey_info.field_length = key->u.ec.params.field_length;
}
} else {
goto fail;
@ -606,6 +608,7 @@ static int sc_pkcs15emu_coolkey_init(sc_pkcs15_card_t *p15card)
break;
case CKO_PUBLIC_KEY:
sc_log(card->ctx, "Processing public key object %d", i);
r = coolkey_get_attribute_ulong(card, &coolkey_obj, CKA_KEY_TYPE, &key_type);
/* default to CKK_RSA */
if (r == SC_ERROR_DATA_OBJECT_NOT_FOUND) {
@ -623,21 +626,21 @@ static int sc_pkcs15emu_coolkey_init(sc_pkcs15_card_t *p15card)
obj_info = &pubkey_info;
memset(&pubkey_info, 0, sizeof(pubkey_info));
r = sc_pkcs15_encode_pubkey_as_spki(card->ctx, key, &pubkey_info.direct.spki.value,
&pubkey_info.direct.spki.len);
&pubkey_info.direct.spki.len);
if (r < 0)
goto fail;
coolkey_get_id(card, &coolkey_obj, &pubkey_info.id);
pubkey_info.path = coolkey_obj.path;
pubkey_info.native = 1;
pubkey_info.native = 1;
pubkey_info.key_reference = coolkey_obj.id;
coolkey_get_usage(card, &coolkey_obj, &pubkey_info.usage);
coolkey_get_access(card, &coolkey_obj, &pubkey_info.access_flags);
if (key_type == CKK_RSA) {
obj_type = SC_PKCS15_TYPE_PUBKEY_RSA;
pubkey_info.modulus_length = key->u.rsa.modulus.len*8;
pubkey_info.modulus_length = key->u.rsa.modulus.len*8;
} else if (key_type == CKK_EC) {
obj_type = SC_PKCS15_TYPE_PUBKEY_EC;
pubkey_info.field_length = key->u.ec.params.field_length;
pubkey_info.field_length = key->u.ec.params.field_length;
} else {
goto fail;
}
@ -647,6 +650,7 @@ static int sc_pkcs15emu_coolkey_init(sc_pkcs15_card_t *p15card)
break;
case CKO_CERTIFICATE:
sc_log(card->ctx, "Processing certificate object %d", i);
obj_info = &cert_info;
memset(&cert_info, 0, sizeof(cert_info));
coolkey_get_id(card, &coolkey_obj, &cert_info.id);

View File

@ -390,11 +390,15 @@ int sc_pkcs15emu_object_add(sc_pkcs15_card_t *p15card, unsigned int type,
unsigned int df_type;
size_t data_len;
SC_FUNC_CALLED(p15card->card->ctx, SC_LOG_DEBUG_VERBOSE);
obj = calloc(1, sizeof(*obj));
if (!obj)
return SC_ERROR_OUT_OF_MEMORY;
if (!obj) {
LOG_FUNC_RETURN(p15card->card->ctx, SC_ERROR_OUT_OF_MEMORY);
}
memcpy(obj, in_obj, sizeof(*obj));
obj->type = type;
obj->type = type;
switch (type & SC_PKCS15_TYPE_CLASS_MASK) {
case SC_PKCS15_TYPE_AUTH:
@ -420,19 +424,19 @@ int sc_pkcs15emu_object_add(sc_pkcs15_card_t *p15card, unsigned int type,
default:
sc_log(p15card->card->ctx, "Unknown PKCS15 object type %d", type);
free(obj);
return SC_ERROR_INVALID_ARGUMENTS;
LOG_FUNC_RETURN(p15card->card->ctx, SC_ERROR_INVALID_ARGUMENTS);
}
obj->data = calloc(1, data_len);
if (obj->data == NULL) {
free(obj);
return SC_ERROR_OUT_OF_MEMORY;
LOG_FUNC_RETURN(p15card->card->ctx, SC_ERROR_OUT_OF_MEMORY);
}
memcpy(obj->data, data, data_len);
obj->df = sc_pkcs15emu_get_df(p15card, df_type);
sc_pkcs15_add_object(p15card, obj);
return SC_SUCCESS;
LOG_FUNC_RETURN(p15card->card->ctx, SC_SUCCESS);
}

View File

@ -78,6 +78,25 @@
#define PCSC_TRACE(reader, desc, rv) do { sc_log(reader->ctx, "%s:" desc ": 0x%08lx\n", reader->name, (unsigned long)((ULONG)rv)); } while (0)
#define PCSC_LOG(ctx, desc, rv) do { sc_log(ctx, desc ": 0x%08lx\n", (unsigned long)((ULONG)rv)); } while (0)
/* #define APDU_LOG_FILE "apdulog" */
#ifdef APDU_LOG_FILE
void APDU_LOG(u8 *rbuf, uint16_t rsize)
{
static FILE *fd = NULL;
u8 *lenb = (u8*)&rsize;
if (fd == NULL) {
fd = fopen(APDU_LOG_FILE, "w");
}
/* First two bytes denote the length */
(void) fwrite(lenb, 2, 1, fd);
(void) fwrite(rbuf, rsize, 1, fd);
fflush(fd);
}
#else
#define APDU_LOG(rbuf, rsize)
#endif
struct pcsc_global_private_data {
int cardmod;
SCARDCONTEXT pcsc_ctx;
@ -305,6 +324,7 @@ static int pcsc_transmit(sc_reader_t *reader, sc_apdu_t *apdu)
goto out;
}
sc_apdu_log(reader->ctx, rbuf, rsize, 0);
APDU_LOG(rbuf, (uint16_t)rsize);
/* set response */
r = sc_apdu_set_resp(reader->ctx, apdu, rbuf, rsize);
@ -402,6 +422,7 @@ static int refresh_attributes(sc_reader_t *reader)
if (memcmp(priv->reader_state.rgbAtr, reader->atr.value, priv->reader_state.cbAtr) != 0) {
reader->atr.len = priv->reader_state.cbAtr;
memcpy(reader->atr.value, priv->reader_state.rgbAtr, reader->atr.len);
APDU_LOG(reader->atr.value, (uint16_t) reader->atr.len);
}
/* Is the reader in use by some other application ? */

View File

@ -49,19 +49,20 @@ sc_simpletlv_put_tag(u8 tag, size_t datalen, u8 *out, size_t outlen, u8 **ptr)
/* tag is just number between 0x01 and 0xFE */
if (tag == 0x00 || tag == 0xff)
return SC_ERROR_INVALID_ARGUMENTS;
if (datalen > 0xffff) {
/* we can't store more than two bytes in Simple TLV */
return SC_ERROR_WRONG_LENGTH;
}
*p++ = tag; /* tag is single byte */
if (datalen < 0xff) {
/* short value up to 255 */
*p++ = (u8)datalen; /* is in the second byte */
} else if (datalen < 0xffff) {
} else {
/* longer values up to 65535 */
*p++ = (u8)0xff; /* first byte is 0xff */
*p++ = (u8)datalen & 0xff;
*p++ = (u8)(datalen >> 8) & 0xff; /* LE */
} else {
/* we can't store more than two bytes in Simple TLV */
return SC_ERROR_WRONG_LENGTH;
}
if (ptr != NULL)
*ptr = p;

View File

@ -3,7 +3,7 @@ include $(top_srcdir)/win32/ltrc.inc
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
EXTRA_DIST = Makefile.mak
SUBDIRS = regression p11test fuzzing
SUBDIRS = regression p11test fuzzing unittests
noinst_PROGRAMS = base64 lottery p15dump pintest prngtest
AM_CPPFLAGS = -I$(top_srcdir)/src

View File

@ -103,7 +103,7 @@ static int fuzz_reader_connect(sc_reader_t *reader)
fuzz_get_chunk(reader, &chunk, &chunk_size);
if (chunk_size > reader->atr.len)
if (chunk_size > reader->atr.len && reader->atr.len > 0)
chunk_size = reader->atr.len;
else
reader->atr.len = chunk_size;

View File

@ -0,0 +1,37 @@
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
EXTRA_DIST = Makefile.mak
if ENABLE_CMOCKA
include $(top_srcdir)/aminclude_static.am
clean-local: code-coverage-clean
distclean-local: code-coverage-dist-clean
noinst_PROGRAMS = asn1 simpletlv
TESTS = asn1 simpletlv
noinst_HEADERS = torture.h
AM_CFLAGS = -I$(top_srcdir)/src/ \
-L$(top_srcdir)/src/libopensc/ \
$(CODE_COVERAGE_CFLAGS) \
$(CMOCKA_CFLAGS)
AM_CPPFLAGS =$(CODE_COVERAGE_CPPFLAGS)
LDADD = $(top_srcdir)/src/libopensc/libopensc.la \
$(CODE_COVERAGE_LIBS) \
$(OPTIONAL_OPENSSL_LIBS) \
$(CMOCKA_LIBS)
asn1_SOURCES = asn1.c
simpletlv_SOURCES = simpletlv.c
if ENABLE_ZLIB
noinst_PROGRAMS += compression
TESTS += compression
compression_SOURCES = compression.c
compression_LDADD = $(LDADD) $(OPTIONAL_ZLIB_LIBS)
endif
endif

View File

@ -0,0 +1,18 @@
TOPDIR = ..\..\..
TARGETS = asn1 compression
OBJECTS = asn1.obj \
compression.obj
$(TOPDIR)\win32\versioninfo.res
all: $(TARGETS)
!INCLUDE $(TOPDIR)\win32\Make.rules.mak
$(TARGETS): $(OBJECTS) $(LIBS)
.c.exe:
cl $(COPTS) /c $<
link $(LINKFLAGS) /pdb:$*.pdb /out:$@ $*.obj $(OBJECTS) $(LIBS)
if EXIST $@.manifest mt -manifest $@.manifest -outputresource:$@;1

509
src/tests/unittests/asn1.c Normal file
View File

@ -0,0 +1,509 @@
/*
* asn1.c: Unit tests for ASN1 parsers
*
* Copyright (C) 2019 Red Hat, Inc.
*
* Author: Jakub Jelen <jjelen@redhat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "torture.h"
#include "libopensc/log.c"
#include "libopensc/asn1.c"
/* The last argument is an OID value */
#define TORTURE_OID(name, asn1_data, ...) \
static void torture_asn1_oid_## name (void **state) \
{ \
u8 data[] = asn1_data; \
size_t datalen = sizeof(data) - 1; \
struct sc_object_id ref_oid = {{__VA_ARGS__}}; \
struct sc_object_id oid; \
int rv; \
u8 *buf = NULL; \
size_t buflen = 0; \
\
rv = sc_asn1_decode_object_id(data, datalen, &oid); \
assert_int_equal(rv, SC_SUCCESS); \
assert_int_equal(sc_compare_oid(&ref_oid, &oid), 1); /* XXX */ \
rv = sc_asn1_encode_object_id(&buf, &buflen, &oid); \
assert_int_equal(rv, SC_SUCCESS); \
assert_int_equal(buflen, datalen); \
assert_memory_equal(buf, data, buflen); \
free(buf); \
}
#define TORTURE_OID_ERROR(name, asn1_data, error) \
static void torture_asn1_oid_## name (void **state) \
{ \
u8 data[] = asn1_data; \
size_t datalen = sizeof(data) - 1; \
struct sc_object_id oid; \
int rv; \
\
rv = sc_asn1_decode_object_id(data, datalen, &oid); \
assert_int_equal(rv, error); \
}
/* Without the tag (0x06) and length */
/* Small OID values */
TORTURE_OID(small, "\x01\x02\x03\x04\x05\x06", 0, 1, 2, 3, 4, 5, 6, -1)
/* Limit what we can fit into the first byte */
TORTURE_OID(limit, "\x7F", 2, 47, -1)
/* The second octet already oveflows to the second byte */
TORTURE_OID(two_byte, "\x81\x00", 2, 48, -1)
/* Existing OID ec publickey */
TORTURE_OID(ecpubkey, "\x2A\x86\x48\xCE\x3D\x02\x01", 1, 2, 840, 10045, 2, 1, -1)
/* Negative tests */
/* Missing second byte, even though indicated with the first bit */
TORTURE_OID_ERROR(missing, "\x81", SC_ERROR_INVALID_ASN1_OBJECT)
/* Missing second byte in later identifiers */
TORTURE_OID_ERROR(missing_second, "\x2A\x48\x81", SC_ERROR_INVALID_ASN1_OBJECT)
/* Non-minimal encoding of first part */
TORTURE_OID_ERROR(non_minimal_second, "\x2A\x80\x01", SC_ERROR_INVALID_ASN1_OBJECT)
/* Non-minimal encoding of first part */
TORTURE_OID_ERROR(non_minimal, "\x80\x01", SC_ERROR_INVALID_ASN1_OBJECT)
/*
* Test undefined behavior of too large parts of OID encoding
*
* The specification does not place any limits to these values, but they
* are internally in opensc stored as ints so it makes sense to reject
* the too-large onese for now, rather than causing undefined overflow.
*
* https://oss-fuzz.com/testcase-detail/5673497895895040
*/
#if INT_MAX == 2147483647
/* 2.5.4.2147483647 (The last part is largest 32 bit integer) */
TORTURE_OID(last_int_max, "\x55\x04\x87\xFF\xFF\xFF\x7F", 2, 5, 4, 2147483647, -1)
/* 2.2147483647.4.3 (The second part is largest 32 bit integer) */
TORTURE_OID(first_int_max, "\x88\x80\x80\x80\x4F\x04\x03", 2, 2147483647, 4, 3, -1)
#else
/* 2.5.4.2147483647 (The last part is largest 32 bit integer) */
TORTURE_OID_ERROR(last_int_max, "\x55\x04\x87\xFF\xFF\xFF\x7F", SC_ERROR_NOT_SUPPORTED)
/* 2.2147483647.4.3 (The second part is largest 32 bit integer) */
TORTURE_OID_ERROR(first_int_max, "\x88\x80\x80\x80\x4F\x04\x03", SC_ERROR_NOT_SUPPORTED)
#endif
/* 2.5.4.2147483648 (The last part is 32 bit integer overflow) */
TORTURE_OID_ERROR(last_32b_overflow, "\x55\x04\x88\x80\x80\x80\x00", SC_ERROR_NOT_SUPPORTED)
/* 2.2147483648.4.3 (The second part is 32 bit integer overflow) */
TORTURE_OID_ERROR(first_32b_overflow, "\x88\x80\x80\x80\x50\x04\x03", SC_ERROR_NOT_SUPPORTED)
/* TODO SC_MAX_OBJECT_ID_OCTETS */
#define TORTURE_INTEGER(name, asn1_data, int_value) \
static void torture_asn1_integer_## name (void **state) \
{ \
u8 data[] = asn1_data; \
size_t datalen = sizeof(data) - 1; \
int value = 0; \
int rv; \
u8 *buf = NULL; \
size_t buflen = 0; \
\
rv = sc_asn1_decode_integer(data, datalen, &value, 1); \
assert_int_equal(rv, SC_SUCCESS); \
assert_int_equal(value, int_value); \
rv = asn1_encode_integer(value, &buf, &buflen); \
assert_int_equal(rv, SC_SUCCESS); \
assert_int_equal(buflen, datalen); \
assert_memory_equal(buf, data, buflen); \
free(buf); \
}
#define TORTURE_INTEGER_ERROR(name, asn1_data, error) \
static void torture_asn1_integer_## name (void **state) \
{ \
u8 data[] = asn1_data; \
size_t datalen = sizeof(data) - 1; \
int value = 0; \
int rv; \
\
rv = sc_asn1_decode_integer(data, datalen, &value, 1); \
assert_int_equal(rv, error); \
}
#define TORTURE_INTEGER_NONSTRICT(name, asn1_data, error, int_value) \
static void torture_asn1_integer_## name (void **state) \
{ \
u8 data[] = asn1_data; \
size_t datalen = sizeof(data) - 1; \
int value = 0; \
int rv; \
\
rv = sc_asn1_decode_integer(data, datalen, &value, 1); \
assert_int_equal(rv, error); \
/* but we can parse them without the strict checking */ \
rv = sc_asn1_decode_integer(data, datalen, &value, 0); \
assert_int_equal(rv, SC_SUCCESS); \
assert_int_equal(value, int_value); \
}
/* Data are without the Tag (0x02) and Length */
/* Positive test cases, mostly corner cases */
TORTURE_INTEGER(zero, "\x00", 0)
TORTURE_INTEGER(one, "\x01", 1)
TORTURE_INTEGER(minus_one, "\xFF", -1)
TORTURE_INTEGER(padded_128, "\x00\x80", 128)
TORTURE_INTEGER(max2, "\x7F\xFF", 32767)
TORTURE_INTEGER(min2, "\x80\x00", -32768)
#if INT_MAX == 2147483647
TORTURE_INTEGER(max4, "\x7F\xFF\xFF\xFF", 2147483647)
TORTURE_INTEGER(min4, "\x80\x00\x00\x00", -2147483648)
#else
TORTURE_INTEGER_ERROR(max4, "\x7F\xFF\xFF\xFF", SC_ERROR_NOT_SUPPORTED)
TORTURE_INTEGER_ERROR(min4, "\x80\x00\x00\x00", SC_ERROR_NOT_SUPPORTED)
#endif
/* Negative test cases */
TORTURE_INTEGER_ERROR(null, "", SC_ERROR_INVALID_ASN1_OBJECT)
TORTURE_INTEGER_ERROR(over, "\x7F\xFF\xFF\xFF\xFF", SC_ERROR_NOT_SUPPORTED)
/* Tests fail in strict mode, but work otherwise */
TORTURE_INTEGER_NONSTRICT(padded_zero, "\x00\x00", SC_ERROR_INVALID_ASN1_OBJECT, 0)
TORTURE_INTEGER_NONSTRICT(padded_one, "\x00\x01", SC_ERROR_INVALID_ASN1_OBJECT, 1)
TORTURE_INTEGER_NONSTRICT(padded_minus_one, "\xFF\xFF", SC_ERROR_INVALID_ASN1_OBJECT, -1)
TORTURE_INTEGER_NONSTRICT(padded_127, "\x00\x7F", SC_ERROR_INVALID_ASN1_OBJECT, 127)
/*
* Test undefined behavior of negative INTEGERS handling.
* https://oss-fuzz.com/testcase-detail/5125815506829312
*
* The issue was not actually the size of the integers, but that first
* negative value wrote ones to the whole integer and it was not possible
* to shift values afterward.
*/
TORTURE_INTEGER(negative, "\xff\x20", -224)
#define TORTURE_BIT_FIELD(name, asn1_data, int_value) \
static void torture_asn1_bit_field_## name (void **state) \
{ \
u8 data[] = asn1_data; \
size_t datalen = sizeof(data) - 1; \
unsigned int value = 0; \
size_t value_len = sizeof(value); \
int rv; \
\
rv = decode_bit_field(data, datalen, &value, value_len); \
assert_int_equal(rv, SC_SUCCESS); \
assert_int_equal(value, int_value); \
}
#define TORTURE_BIT_FIELD_ERROR(name, asn1_data, error) \
static void torture_asn1_bit_field_## name (void **state) \
{ \
u8 data[] = asn1_data; \
size_t datalen = sizeof(data) - 1; \
unsigned int value = 0; \
size_t value_len = sizeof(value); \
int rv; \
\
rv = decode_bit_field(data, datalen, &value, value_len); \
assert_int_equal(rv, error); \
}
/* Without the Tag (0x03) and Length */
/* Simple value 0 */
TORTURE_BIT_FIELD(zero, "\x07\x00", 0)
/* Simple value 1 */
TORTURE_BIT_FIELD(one, "\x07\x80", 1)
/* This is the last value that can be represented in the unsigned int */
TORTURE_BIT_FIELD(uint_max, "\x00\xff\xff\xff\xff", UINT_MAX)
/* Valid padding */
TORTURE_BIT_FIELD(padding, "\x01\xfe", 127)
/* Empty bit field needs zero padding */
TORTURE_BIT_FIELD(zero_only, "\x00", 0)
/* Negative test cases */
/* Too large unused bits field */
TORTURE_BIT_FIELD_ERROR(large_unused_bits, "\x20\xff\xff\xff\xff", SC_ERROR_INVALID_ASN1_OBJECT)
/* Too large to represent in the unsigned int type */
TORTURE_BIT_FIELD_ERROR(too_large, "\x00\xff\xff\xff\xff\xff", SC_ERROR_BUFFER_TOO_SMALL)
/* Invalid (non-zero bits) padding */
TORTURE_BIT_FIELD_ERROR(invalid_padding, "\x01\xff", SC_ERROR_INVALID_ASN1_OBJECT)
/* Empty bit field with non-zero zero-bits */
TORTURE_BIT_FIELD_ERROR(zero_invalid, "\x07", SC_ERROR_INVALID_ASN1_OBJECT)
/* Empty BIT FIELD is not valid */
TORTURE_BIT_FIELD_ERROR(empty, "", SC_ERROR_INVALID_ASN1_OBJECT)
/* Setup context */
static int setup_sc_context(void **state)
{
sc_context_t *ctx = NULL;
int rv;
rv = sc_establish_context(&ctx, "fuzz");
assert_non_null(ctx);
assert_int_equal(rv, SC_SUCCESS);
*state = ctx;
return 0;
}
/* Cleanup context */
static int teardown_sc_context(void **state)
{
sc_context_t *ctx = *state;
int rv;
rv = sc_release_context(ctx);
assert_int_equal(rv, SC_SUCCESS);
return 0;
}
#define DEPTH 1
static void torture_asn1_decode_entry_octet_string_empty(void **state)
{
sc_context_t *ctx = *state;
/* Skipped the Tag and Length (0x04, 0x00) */
const u8 octet_string[0] = {};
struct sc_asn1_entry asn1_struct[2] = {
{ "direct", SC_ASN1_OCTET_STRING, SC_ASN1_CTX | SC_ASN1_CONS, SC_ASN1_ALLOC, NULL, NULL },
{ NULL, 0, 0, 0, NULL, NULL }
};
u8 *result = NULL;
size_t resultlen = 0;
int rv;
/* set the pointers to the expected results */
sc_format_asn1_entry(asn1_struct, &result, &resultlen, 0);
rv = asn1_decode_entry(ctx, asn1_struct, octet_string, 0, DEPTH);
assert_int_equal(rv, SC_SUCCESS);
assert_int_equal(resultlen, 0);
assert_null(result);
}
static void torture_asn1_decode_entry_octet_string_short(void **state)
{
sc_context_t *ctx = *state;
/* Skipped the Tag and Length (0x04, 0x01) */
const u8 octet_string[] = {0xbc};
struct sc_asn1_entry asn1_struct[2] = {
{ "direct", SC_ASN1_OCTET_STRING, SC_ASN1_CTX | SC_ASN1_CONS,
SC_ASN1_ALLOC, NULL, NULL },
{ NULL, 0, 0, 0, NULL, NULL }
};
u8 *result = NULL;
size_t resultlen = 0;
int rv;
/* set the pointers to the expected results */
sc_format_asn1_entry(asn1_struct, &result, &resultlen, 0);
rv = asn1_decode_entry(ctx, asn1_struct, octet_string, sizeof(octet_string), DEPTH);
assert_int_equal(rv, SC_SUCCESS);
assert_int_equal(resultlen, sizeof(octet_string));
assert_memory_equal(result, octet_string, resultlen);
}
/* In case of we expect UNSIGNED value from this, the parser already takes
* care of removing initial zero byte, which is used to avoid mismatches with
* negative integers */
static void torture_asn1_decode_entry_octet_string_unsigned(void **state)
{
sc_context_t *ctx = *state;
/* Skipped the Tag and Length (0x04, 0x02) */
const u8 octet_string[] = {0x00, 0xff};
struct sc_asn1_entry asn1_struct[2] = {
{ "direct", SC_ASN1_OCTET_STRING, SC_ASN1_CTX | SC_ASN1_CONS,
SC_ASN1_ALLOC | SC_ASN1_UNSIGNED, NULL, NULL },
{ NULL, 0, 0, 0, NULL, NULL }
};
u8 *result = NULL;
size_t resultlen = 0;
int rv;
/* set the pointers to the expected results */
sc_format_asn1_entry(asn1_struct, &result, &resultlen, 0);
rv = asn1_decode_entry(ctx, asn1_struct, octet_string, sizeof(octet_string), DEPTH);
assert_int_equal(rv, SC_SUCCESS);
assert_int_equal(resultlen, sizeof(octet_string) -1);
assert_memory_equal(result, octet_string + 1, resultlen);
}
static void torture_asn1_decode_entry_octet_string_pre_allocated(void **state)
{
sc_context_t *ctx = *state;
/* Skipped the Tag and Length (0x04, 0x02) */
const u8 octet_string[] = {0x01, 0x02, 0x03, 0x04};
struct sc_asn1_entry asn1_struct[2] = {
{ "direct", SC_ASN1_OCTET_STRING, SC_ASN1_CTX | SC_ASN1_CONS, 0, NULL, NULL },
{ NULL, 0, 0, 0, NULL, NULL }
};
u8 result[8];
size_t resultlen = sizeof(result);
int rv;
/* set the pointers to the expected results */
sc_format_asn1_entry(asn1_struct, &result, &resultlen, 0);
rv = asn1_decode_entry(ctx, asn1_struct, octet_string, sizeof(octet_string), DEPTH);
assert_int_equal(rv, SC_SUCCESS);
assert_int_equal(resultlen, sizeof(octet_string));
assert_memory_equal(result, octet_string, resultlen);
}
static void torture_asn1_decode_entry_octet_string_pre_allocated_truncate(void **state)
{
sc_context_t *ctx = *state;
/* Skipped the Tag and Length (0x04, 0x02) */
const u8 octet_string[] = {0x01, 0x02, 0x03, 0x04};
struct sc_asn1_entry asn1_struct[2] = {
{ "direct", SC_ASN1_OCTET_STRING, SC_ASN1_CTX | SC_ASN1_CONS, 0, NULL, NULL },
{ NULL, 0, 0, 0, NULL, NULL }
};
u8 result[2];
size_t resultlen = sizeof(result);
int rv;
/* set the pointers to the expected results */
sc_format_asn1_entry(asn1_struct, &result, &resultlen, 0);
rv = asn1_decode_entry(ctx, asn1_struct, octet_string, sizeof(octet_string), DEPTH);
assert_int_equal(rv, SC_SUCCESS);
assert_int_equal(resultlen, sizeof(result));
assert_memory_equal(result, octet_string, resultlen);
}
static void torture_asn1_decode_entry_bit_string_empty(void **state)
{
sc_context_t *ctx = *state;
/* Skipped the Tag and Length (0x04, 0x00) */
const u8 bit_string[] = {0x00};
struct sc_asn1_entry asn1_struct[2] = {
{ "signatureValue", SC_ASN1_BIT_STRING, SC_ASN1_TAG_BIT_STRING, SC_ASN1_ALLOC, NULL, NULL },
{ NULL, 0, 0, 0, NULL, NULL }
};
u8 *result = NULL;
size_t resultlen = 0;
int rv;
/* set the pointers to the expected results */
sc_format_asn1_entry(asn1_struct, &result, &resultlen, 0);
rv = asn1_decode_entry(ctx, asn1_struct, bit_string, sizeof(bit_string), DEPTH);
assert_int_equal(rv, SC_SUCCESS);
assert_int_equal(resultlen, 0);
assert_null(result);
}
static void torture_asn1_decode_entry_bit_string_short(void **state)
{
sc_context_t *ctx = *state;
/* Skipped the Tag and Length (0x04, 0x00) */
const u8 bit_string[] = {0x00, 0xFE};
/* By default, the bit string has MSB on the right. Yay */
const u8 exp_result[] = {0x7F};
struct sc_asn1_entry asn1_struct[2] = {
{ "signatureValue", SC_ASN1_BIT_STRING, SC_ASN1_TAG_BIT_STRING, SC_ASN1_ALLOC, NULL, NULL },
{ NULL, 0, 0, 0, NULL, NULL }
};
u8 *result = NULL;
size_t resultlen = 0;
int rv;
/* set the pointers to the expected results */
sc_format_asn1_entry(asn1_struct, &result, &resultlen, 0);
rv = asn1_decode_entry(ctx, asn1_struct, bit_string, sizeof(bit_string), DEPTH);
assert_int_equal(rv, SC_SUCCESS);
assert_int_equal(resultlen, 8);
assert_memory_equal(exp_result, result, resultlen/8);
}
/* This modification does not invert the bit order */
static void torture_asn1_decode_entry_bit_string_ni(void **state)
{
sc_context_t *ctx = *state;
/* Skipped the Tag and Length (0x04, 0x00) */
const u8 bit_string[] = {0x00, 0xFE};
struct sc_asn1_entry asn1_struct[2] = {
{ "signatureValue", SC_ASN1_BIT_STRING_NI, SC_ASN1_TAG_BIT_STRING, SC_ASN1_ALLOC, NULL, NULL },
{ NULL, 0, 0, 0, NULL, NULL }
};
u8 *result = NULL;
size_t resultlen = 0;
int rv;
/* set the pointers to the expected results */
sc_format_asn1_entry(asn1_struct, &result, &resultlen, 0);
rv = asn1_decode_entry(ctx, asn1_struct, bit_string, sizeof(bit_string), DEPTH);
assert_int_equal(rv, SC_SUCCESS);
assert_int_equal(resultlen, 8);
assert_memory_equal(bit_string + 1, result, resultlen/8);
}
int main(void)
{
int rc;
struct CMUnitTest tests[] = {
/* INTEGER */
cmocka_unit_test(torture_asn1_integer_zero),
cmocka_unit_test(torture_asn1_integer_one),
cmocka_unit_test(torture_asn1_integer_minus_one),
cmocka_unit_test(torture_asn1_integer_padded_128),
cmocka_unit_test(torture_asn1_integer_max2),
cmocka_unit_test(torture_asn1_integer_min2),
cmocka_unit_test(torture_asn1_integer_max4),
cmocka_unit_test(torture_asn1_integer_min4),
cmocka_unit_test(torture_asn1_integer_null),
cmocka_unit_test(torture_asn1_integer_over),
cmocka_unit_test(torture_asn1_integer_padded_zero),
cmocka_unit_test(torture_asn1_integer_padded_one),
cmocka_unit_test(torture_asn1_integer_padded_minus_one),
cmocka_unit_test(torture_asn1_integer_padded_127),
cmocka_unit_test(torture_asn1_integer_negative),
/* OBJECT ID */
cmocka_unit_test(torture_asn1_oid_small),
cmocka_unit_test(torture_asn1_oid_limit),
cmocka_unit_test(torture_asn1_oid_two_byte),
cmocka_unit_test(torture_asn1_oid_ecpubkey),
cmocka_unit_test(torture_asn1_oid_missing),
cmocka_unit_test(torture_asn1_oid_missing_second),
cmocka_unit_test(torture_asn1_oid_last_int_max),
cmocka_unit_test(torture_asn1_oid_first_int_max),
cmocka_unit_test(torture_asn1_oid_last_32b_overflow),
cmocka_unit_test(torture_asn1_oid_first_32b_overflow),
cmocka_unit_test(torture_asn1_oid_non_minimal),
cmocka_unit_test(torture_asn1_oid_non_minimal_second),
/* BIT FIELD */
cmocka_unit_test(torture_asn1_bit_field_zero),
cmocka_unit_test(torture_asn1_bit_field_one),
cmocka_unit_test(torture_asn1_bit_field_uint_max),
cmocka_unit_test(torture_asn1_bit_field_padding),
cmocka_unit_test(torture_asn1_bit_field_zero_only),
cmocka_unit_test(torture_asn1_bit_field_large_unused_bits),
cmocka_unit_test(torture_asn1_bit_field_too_large),
cmocka_unit_test(torture_asn1_bit_field_invalid_padding),
cmocka_unit_test(torture_asn1_bit_field_zero_invalid),
cmocka_unit_test(torture_asn1_bit_field_empty),
/* decode_entry(): OCTET STRING */
cmocka_unit_test_setup_teardown(torture_asn1_decode_entry_octet_string_empty,
setup_sc_context, teardown_sc_context),
cmocka_unit_test_setup_teardown(torture_asn1_decode_entry_octet_string_short,
setup_sc_context, teardown_sc_context),
cmocka_unit_test_setup_teardown(torture_asn1_decode_entry_octet_string_unsigned,
setup_sc_context, teardown_sc_context),
cmocka_unit_test_setup_teardown(torture_asn1_decode_entry_octet_string_pre_allocated,
setup_sc_context, teardown_sc_context),
cmocka_unit_test_setup_teardown(torture_asn1_decode_entry_octet_string_pre_allocated_truncate,
setup_sc_context, teardown_sc_context),
/* decode_entry(): BIT STRING */
cmocka_unit_test_setup_teardown(torture_asn1_decode_entry_bit_string_empty,
setup_sc_context, teardown_sc_context),
cmocka_unit_test_setup_teardown(torture_asn1_decode_entry_bit_string_short,
setup_sc_context, teardown_sc_context),
cmocka_unit_test_setup_teardown(torture_asn1_decode_entry_bit_string_ni,
setup_sc_context, teardown_sc_context),
};
rc = cmocka_run_group_tests(tests, NULL, NULL);
return rc;
}

View File

@ -0,0 +1,309 @@
/*
* compression.c: Unit tests for compression API
*
* Copyright (C) 2019 Red Hat, Inc.
*
* Author: Jakub Jelen <jjelen@redhat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "torture.h"
#include "libopensc/log.c"
#include "libopensc/compression.c"
/* The data from fuzzer has valid header (0x1f, 0x8b), but anything
* after that is just garbage. The first call to inflate()
* returns Z_STREAM_END, calculated number of processed bytes 0, while
* keeping the allocated buffers.
*/
u8 invalid_data[] = {
0x1f, 0x8b, 0x08, 0x10, 0x08, 0x78, 0x10, 0x1f,
0x8b, 0x08, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x8b, 0x08,
0x10, 0x08, 0x78, 0x10, 0x1f, 0x8b, 0x08, 0x00,
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1f, 0x8b, 0x08, 0x10, 0x08, 0x78,
0x10, 0x1f, 0x8b, 0x08, 0x61, 0x61, 0x61, 0x61,
0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x08, 0x00,
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1f, 0x8b, 0x08, 0x10, 0x08, 0x78,
0x10, 0x1f, 0x8b};
/* Generated using
* $ echo "test" > /tmp/test
* $ gzip -c /tmp/test > /tmp/test.gz
* $ hexdump -C /tmp/test.gz
*/
u8 valid_data[] = {
0x1f, 0x8b, 0x08, 0x08, 0x5d, 0xd8, 0xcb, 0x5d,
0x00, 0x03, 0x74, 0x65, 0x73, 0x74, 0x00, 0x2b,
0x49, 0x2d, 0x2e, 0xe1, 0x02, 0x00, 0xc6, 0x35,
0xb9, 0x3b, 0x05, 0x00, 0x00, 0x00};
/* Generated as in the previous test case with some added mess on the end
*/
u8 invalid_suffix_data[] = {
0x1f, 0x8b, 0x08, 0x08, 0x5d, 0xd8, 0xcb, 0x5d,
0x00, 0x03, 0x74, 0x65, 0x73, 0x74, 0x00, 0x2b,
0x49, 0x2d, 0x2e, 0xe1, 0x02, 0x00, 0xc6, 0x35,
0xb9, 0x3b, 0x05, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff};
static void torture_compression_decompress_alloc_empty(void **state)
{
u8 *buf = NULL;
u8 *data = NULL;
size_t buflen = 0;
size_t datalen = 0;
int rv;
rv = sc_decompress_alloc(&buf, &buflen, data, datalen, COMPRESSION_AUTO);
assert_int_equal(rv, SC_ERROR_UNKNOWN_DATA_RECEIVED);
assert_int_equal(buflen, 0);
assert_null(buf);
}
static void torture_compression_decompress_alloc_gzip_empty(void **state)
{
u8 *buf = NULL;
u8 *data = NULL;
size_t buflen = 0;
size_t datalen = 0;
int rv;
rv = sc_decompress_alloc(&buf, &buflen, data, datalen, COMPRESSION_GZIP);
assert_int_equal(rv, SC_ERROR_UNKNOWN_DATA_RECEIVED);
assert_int_equal(buflen, 0);
assert_null(buf);
}
static void torture_compression_decompress_alloc_zlib_empty(void **state)
{
u8 *buf = NULL;
u8 *data = NULL;
size_t buflen = 0;
size_t datalen = 0;
int rv;
rv = sc_decompress_alloc(&buf, &buflen, data, datalen, COMPRESSION_ZLIB);
assert_int_equal(rv, SC_ERROR_UNKNOWN_DATA_RECEIVED);
assert_int_equal(buflen, 0);
assert_null(buf);
}
static void torture_compression_decompress_alloc_header(void **state)
{
u8 *buf = NULL;
u8 data[] = {0x1f, 0x8b};
size_t buflen = 0;
size_t datalen = sizeof(data);
int rv;
rv = sc_decompress_alloc(&buf, &buflen, data, datalen, COMPRESSION_AUTO);
assert_int_equal(rv, SC_ERROR_UNKNOWN_DATA_RECEIVED);
assert_int_equal(buflen, 0);
assert_null(buf);
}
static void torture_compression_decompress_alloc_header_invalid(void **state)
{
u8 *buf = NULL;
u8 data[] = {0x1e, 0x8a};
size_t buflen = 0;
size_t datalen = sizeof(data);
int rv;
rv = sc_decompress_alloc(&buf, &buflen, data, datalen, COMPRESSION_AUTO);
assert_int_equal(rv, SC_ERROR_UNKNOWN_DATA_RECEIVED);
assert_int_equal(buflen, 0);
assert_null(buf);
}
static void torture_compression_decompress_alloc_invalid(void **state)
{
u8 *buf = NULL;
size_t buflen = 0;
size_t datalen = sizeof(invalid_data);
int rv;
rv = sc_decompress_alloc(&buf, &buflen, invalid_data, datalen, COMPRESSION_AUTO);
assert_int_equal(rv, SC_ERROR_UNKNOWN_DATA_RECEIVED);
assert_int_equal(buflen, 0);
assert_null(buf);
}
static void torture_compression_decompress_alloc_valid(void **state)
{
u8 *buf = NULL;
size_t buflen = 0;
size_t datalen = sizeof(valid_data);
int rv;
rv = sc_decompress_alloc(&buf, &buflen, valid_data, datalen, COMPRESSION_AUTO);
assert_int_equal(rv, SC_SUCCESS);
assert_int_equal(buflen, 5);
assert_memory_equal(buf, "test\x0a", 5);
}
static void torture_compression_decompress_alloc_invalid_suffix(void **state)
{
u8 *buf = NULL;
size_t buflen = 0;
size_t datalen = sizeof(invalid_suffix_data);
int rv;
rv = sc_decompress_alloc(&buf, &buflen, invalid_suffix_data, datalen, COMPRESSION_AUTO);
assert_int_equal(rv, SC_SUCCESS); /* TODO Is this fine? */
assert_int_equal(buflen, 5);
assert_memory_equal(buf, "test\x0a", 5);
}
/* Decompress without allocation */
static void torture_compression_decompress_empty(void **state)
{
u8 buf[1024];
u8 *data = NULL;
size_t buflen = sizeof(buf);
size_t datalen = 0;
int rv;
rv = sc_decompress(buf, &buflen, data, datalen, COMPRESSION_AUTO);
assert_int_equal(rv, SC_ERROR_UNKNOWN_DATA_RECEIVED);
assert_int_equal(buflen, sizeof(buf)); /* Was not touched */
}
static void torture_compression_decompress_gzip_empty(void **state)
{
u8 buf[1024];
u8 *data = NULL;
size_t buflen = sizeof(buf);
size_t datalen = 0;
int rv;
rv = sc_decompress(buf, &buflen, data, datalen, COMPRESSION_GZIP);
assert_int_equal(rv, SC_ERROR_UNKNOWN_DATA_RECEIVED);
assert_int_equal(buflen, sizeof(buf));
}
static void torture_compression_decompress_zlib_empty(void **state)
{
u8 buf[1024];
u8 *data = NULL;
size_t buflen = sizeof(buf);
size_t datalen = 0;
int rv;
rv = sc_decompress(buf, &buflen, data, datalen, COMPRESSION_ZLIB);
assert_int_equal(rv, SC_ERROR_UNKNOWN_DATA_RECEIVED);
assert_int_equal(buflen, 0);
}
static void torture_compression_decompress_header(void **state)
{
u8 buf[1024];
u8 data[] = {0x1f, 0x8b};
size_t buflen = sizeof(buf);
size_t datalen = sizeof(data);
int rv;
rv = sc_decompress(buf, &buflen, data, datalen, COMPRESSION_AUTO);
assert_int_equal(rv, SC_ERROR_UNKNOWN_DATA_RECEIVED);
assert_int_equal(buflen, 0);
}
static void torture_compression_decompress_header_invalid(void **state)
{
u8 buf[1024];
u8 data[] = {0x1e, 0x8a};
size_t buflen = sizeof(buf);
size_t datalen = sizeof(data);
int rv;
rv = sc_decompress(buf, &buflen, data, datalen, COMPRESSION_AUTO);
assert_int_equal(rv, SC_ERROR_UNKNOWN_DATA_RECEIVED);
assert_int_equal(buflen, 0);
}
static void torture_compression_decompress_invalid(void **state)
{
u8 buf[1024];
size_t buflen = sizeof(buf);
size_t datalen = sizeof(invalid_data);
int rv;
rv = sc_decompress(buf, &buflen, invalid_data, datalen, COMPRESSION_AUTO);
assert_int_equal(rv, SC_ERROR_UNKNOWN_DATA_RECEIVED);
assert_int_equal(buflen, 0);
}
static void torture_compression_decompress_valid(void **state)
{
u8 buf[1024];
size_t buflen = sizeof(buf);
size_t datalen = sizeof(valid_data);
int rv;
rv = sc_decompress(buf, &buflen, valid_data, datalen, COMPRESSION_AUTO);
assert_int_equal(rv, SC_SUCCESS);
assert_int_equal(buflen, 5);
assert_memory_equal(buf, "test\x0a", 5);
}
static void torture_compression_decompress_invalid_suffix(void **state)
{
u8 buf[1024];
size_t buflen = sizeof(buf);
size_t datalen = sizeof(invalid_suffix_data);
int rv;
rv = sc_decompress(buf, &buflen, invalid_suffix_data, datalen, COMPRESSION_AUTO);
assert_int_equal(rv, SC_SUCCESS); /* TODO Is this fine? */
assert_int_equal(buflen, 5);
assert_memory_equal(buf, "test\x0a", 5);
}
int main(void)
{
int rc;
struct CMUnitTest tests[] = {
/* Decompress alloc */
cmocka_unit_test(torture_compression_decompress_alloc_empty),
cmocka_unit_test(torture_compression_decompress_alloc_gzip_empty),
cmocka_unit_test(torture_compression_decompress_alloc_zlib_empty),
cmocka_unit_test(torture_compression_decompress_alloc_header),
cmocka_unit_test(torture_compression_decompress_alloc_header_invalid),
cmocka_unit_test(torture_compression_decompress_alloc_invalid),
cmocka_unit_test(torture_compression_decompress_alloc_invalid_suffix),
cmocka_unit_test(torture_compression_decompress_alloc_valid),
/* Decompress */
cmocka_unit_test(torture_compression_decompress_empty),
cmocka_unit_test(torture_compression_decompress_gzip_empty),
cmocka_unit_test(torture_compression_decompress_zlib_empty),
cmocka_unit_test(torture_compression_decompress_header),
cmocka_unit_test(torture_compression_decompress_header_invalid),
cmocka_unit_test(torture_compression_decompress_invalid),
cmocka_unit_test(torture_compression_decompress_invalid_suffix),
cmocka_unit_test(torture_compression_decompress_valid),
};
rc = cmocka_run_group_tests(tests, NULL, NULL);
return rc;
}

View File

@ -0,0 +1,151 @@
/*
* asn1.c: Unit tests for SimpleTLV parser and encoder
*
* Copyright (C) 2019 Red Hat, Inc.
*
* Author: Jakub Jelen <jjelen@redhat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "torture.h"
#include "libopensc/sc.c"
#include "libopensc/simpletlv.c"
static void torture_simpletlv_read_tag_null(void **state)
{
const u8 *data = NULL;
size_t datalen = 0;
u8 tag = 0;
size_t taglen = 0;
int rv;
rv = sc_simpletlv_read_tag(&data, datalen, &tag, &taglen);
assert_int_equal(rv, SC_ERROR_INVALID_TLV_OBJECT);
assert_int_equal(tag, 0);
assert_int_equal(taglen, 0);
}
#define TORTURE_READ_TAG(name, data, tag_value, len_value, error) \
static void torture_simpletlv_read_tag_## name (void **state) \
{ \
u8 buf[] = data; \
const u8 *bufptr = buf; \
size_t buflen = sizeof(buf) - 1; \
u8 tag = 0; \
size_t taglen = 0; \
int rv; \
\
rv = sc_simpletlv_read_tag(&bufptr, buflen, &tag, &taglen); \
assert_int_equal(rv, error); \
assert_int_equal(tag, tag_value); \
assert_int_equal(taglen, len_value); \
}
#define TORTURE_READ_TAG_SUCCESS(name, data, tag_value, len_value) \
TORTURE_READ_TAG(name, data, tag_value, len_value, SC_SUCCESS)
#define TORTURE_READ_TAG_ERROR(name, data, error) \
TORTURE_READ_TAG(name, data, 0, 0, error)
TORTURE_READ_TAG_ERROR(short, "\x42", SC_ERROR_INVALID_TLV_OBJECT)
TORTURE_READ_TAG_SUCCESS(minimal,
"\x42\x00", 0x42, 0)
TORTURE_READ_TAG_SUCCESS(minimal2,
"\x42\x00", 0x42, 0)
TORTURE_READ_TAG_SUCCESS(valid_short,
"\x42\x02\x01\x02", 0x42, 2)
TORTURE_READ_TAG_ERROR(incomplete_length,
"\x42\xff", SC_ERROR_INVALID_TLV_OBJECT)
TORTURE_READ_TAG_SUCCESS(long_length,
"\x42\xff\x00\x00", 0x42, 0)
TORTURE_READ_TAG(missing_data,
"\x42\xff\x02\x00", 0x42, 2, SC_ERROR_TLV_END_OF_CONTENTS)
TORTURE_READ_TAG_SUCCESS(valid_long,
"\x42\xff\x02\x00\x01\x02", 0x42, 2)
static void torture_simpletlv_put_tag_null(void **state)
{
u8 *data = NULL;
size_t datalen = 0;
u8 *outptr = NULL;
int rv;
rv = sc_simpletlv_put_tag(0x42, 2, data, datalen, &outptr);
assert_int_equal(rv, SC_ERROR_INVALID_ARGUMENTS);
assert_null(outptr);
}
#define TORTURE_PUT_TAG(name, tag, taglen, data_len, exp_data, error) \
static void torture_simpletlv_put_tag_## name(void **state) \
{ \
u8 data[data_len] = {}; \
size_t datalen = sizeof(data); \
u8 *outptr = NULL; \
int rv; \
\
rv = sc_simpletlv_put_tag(tag, taglen, data, datalen, &outptr); \
assert_int_equal(rv, error); \
assert_memory_equal(data, exp_data, MIN(sizeof(data), sizeof(exp_data))); \
if (rv == SC_SUCCESS) { \
assert_non_null(outptr); \
} else { \
assert_null(outptr); \
} \
}
#define TORTURE_PUT_TAG_ERROR(name, tag, taglen, data_len, error) \
TORTURE_PUT_TAG(name, tag, taglen, data_len, "", error)
#define TORTURE_PUT_TAG_SUCCESS(name, tag, taglen, data_len, exp_data) \
TORTURE_PUT_TAG(name, tag, taglen, data_len, exp_data, SC_SUCCESS)
TORTURE_PUT_TAG_ERROR(too_small, 0x42, 2, 1, SC_ERROR_INVALID_ARGUMENTS)
TORTURE_PUT_TAG_SUCCESS(valid_short, 0x42, 2, 2, "\x42\x02")
TORTURE_PUT_TAG_ERROR(invalid_tag, 0x00, 2, 2, SC_ERROR_INVALID_ARGUMENTS)
TORTURE_PUT_TAG_ERROR(invalid_tag2, 0xff, 2, 2, SC_ERROR_INVALID_ARGUMENTS)
TORTURE_PUT_TAG_SUCCESS(max_short, 0x42, 0xfe, 2, "\x42\xfe")
TORTURE_PUT_TAG_ERROR(too_long_length, 0x42, 512, 3, SC_ERROR_INVALID_ARGUMENTS)
TORTURE_PUT_TAG_SUCCESS(valid_long, 0x42, 512, 4, "\x42\xff\x00\x02")
TORTURE_PUT_TAG_SUCCESS(first_long, 0x42, 0xff, 4, "\x42\xff\xff\x00")
TORTURE_PUT_TAG_SUCCESS(last_long, 0x42, 0xffff, 4, "\x42\xff\xff\xff")
TORTURE_PUT_TAG_ERROR(too_large_length, 0x42, 0x10000, 4, SC_ERROR_WRONG_LENGTH)
int main(void)
{
int rc;
struct CMUnitTest tests[] = {
/* simpletlv_read_tag() */
cmocka_unit_test(torture_simpletlv_read_tag_null),
cmocka_unit_test(torture_simpletlv_read_tag_short),
cmocka_unit_test(torture_simpletlv_read_tag_minimal),
cmocka_unit_test(torture_simpletlv_read_tag_minimal2),
cmocka_unit_test(torture_simpletlv_read_tag_valid_short),
cmocka_unit_test(torture_simpletlv_read_tag_incomplete_length),
cmocka_unit_test(torture_simpletlv_read_tag_long_length),
cmocka_unit_test(torture_simpletlv_read_tag_missing_data),
cmocka_unit_test(torture_simpletlv_read_tag_valid_long),
/* simpletlv_put_tag() */
cmocka_unit_test(torture_simpletlv_put_tag_null),
cmocka_unit_test(torture_simpletlv_put_tag_too_small),
cmocka_unit_test(torture_simpletlv_put_tag_valid_short),
cmocka_unit_test(torture_simpletlv_put_tag_invalid_tag),
cmocka_unit_test(torture_simpletlv_put_tag_invalid_tag2),
cmocka_unit_test(torture_simpletlv_put_tag_max_short),
cmocka_unit_test(torture_simpletlv_put_tag_too_long_length),
cmocka_unit_test(torture_simpletlv_put_tag_valid_long),
cmocka_unit_test(torture_simpletlv_put_tag_first_long),
cmocka_unit_test(torture_simpletlv_put_tag_last_long),
cmocka_unit_test(torture_simpletlv_put_tag_too_large_length),
};
rc = cmocka_run_group_tests(tests, NULL, NULL);
return rc;
}

View File

@ -0,0 +1,33 @@
/*
* torture.h: Unit tests in OpenSC
*
* Copyright (C) 2019 Red Hat, Inc.
*
* Author: Jakub Jelen <jjelen@redhat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef P11TEST_COMMON_H
#define P11TEST_COMMON_H
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <setjmp.h>
#include <cmocka.h>
#endif /* P11TEST_COMMON_H */

View File

@ -154,7 +154,7 @@ soc_info(sc_context_t *ctx, sc_card_t *card)
&& cla == SC_ASN1_TAG_UNIVERSAL && tag == SC_ASN1_TAG_INTEGER) {
int applet_count = 0;
/* number of applets */
if (SC_SUCCESS == sc_asn1_decode_integer(p, length, &applet_count)) {
if (SC_SUCCESS == sc_asn1_decode_integer(p, length, &applet_count, 0)) {
printf("SoCManager knows %d applet%s%s\n", applet_count,
applet_count == 1 ? "" : "s", applet_count == 0 ? "" : ":");
/* AID of client applet #x */

View File

@ -1,6 +1,7 @@
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
dist_noinst_SCRIPTS = test-manpage.sh \
dist_noinst_SCRIPTS = common.sh \
test-manpage.sh \
test-fuzzing.sh \
test-pkcs11-tool-test.sh \
test-pkcs11-tool-sign-verify.sh \
@ -12,5 +13,4 @@ TESTS = \
test-pkcs11-tool-test.sh \
test-pkcs11-tool-allowed-mechanisms.sh
XFAIL_TESTS = \
test-pkcs11-tool-test.sh \
test-pkcs11-tool-allowed-mechanisms.sh
test-pkcs11-tool-test.sh

View File

@ -6,6 +6,7 @@ PIN="123456"
PKCS11_TOOL="../src/tools/pkcs11-tool"
softhsm_paths="/usr/local/lib/softhsm/libsofthsm2.so \
/usr/lib/softhsm/libsofthsm2.so
/usr/lib64/pkcs11/libsofthsm2.so \
/usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so"

View File

@ -9,9 +9,10 @@ if [[ ! -f $P11LIB ]]; then
echo "WARNINIG: The SoftHSM is not installed. Can not run this test"
exit 77;
fi
# The Ubuntu has old softhsm version not supporting this feature
grep "Ubuntu 18.04" /etc/issue && echo "WARNING: Not supported on Ubuntu 18.04" && exit 77
softhsm_initialize
# XXX This is broken in currently released SoftHSM
# P11LIB=/home/jjelen/devel/SoftHSMv2/src/lib/.libs/libsofthsm2.so
echo "======================================================="
echo "Generate key-pair with CKA_ALLOWED_MECHANISMS"

View File

@ -49,6 +49,9 @@ for HASH in "" "SHA1" "SHA224" "SHA256" "SHA384" "SHA512"; do
continue; # This one is broken
fi
# Ubuntu SoftHSM version does not support RSA-PSS
grep "Ubuntu 18.04" /etc/issue && echo "WARNING: Not supported on Ubuntu 18.04" && continue
echo
echo "======================================================="
echo "$METHOD: Sign & Verify (KEY $SIGN_KEY)"

View File

@ -9,6 +9,10 @@ if [[ ! -f $P11LIB ]]; then
echo "WARNINIG: The SoftHSM is not installed. Can not run this test"
exit 77;
fi
# The Ubuntu has old softhsm version not supporting this feature
grep "Ubuntu 18.04" /etc/issue && echo "WARNING: Not supported on Ubuntu 18.04" && exit 77
card_setup
echo "======================================================="