Merge pull request #1830 from Jakuje/fuzz
Introduce unit tests and address more oss-fuzz issues (mostly ASN1 parser)
This commit is contained in:
commit
5c55546685
|
@ -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
|
||||
|
|
|
@ -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 &
|
||||
|
|
|
@ -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)"
|
||||
|
|
|
@ -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}")
|
||||
|
|
|
@ -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"
|
||||
])
|
||||
])
|
|
@ -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"
|
||||
])
|
||||
])
|
|
@ -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])
|
||||
])
|
|
@ -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])[
|
||||
])
|
||||
])
|
|
@ -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])
|
||||
])
|
|
@ -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
|
||||
])
|
|
@ -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="\""
|
||||
])
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(¶ms.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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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 ? */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -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;
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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)"
|
||||
|
|
|
@ -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 "======================================================="
|
||||
|
|
Loading…
Reference in New Issue