Bug 1317947 - land NSS ee21c9892907, r=me

This commit is contained in:
Franziskus Kiefer 2017-01-21 14:23:56 +01:00
parent 59f6549539
commit 3594725777
94 changed files with 3262 additions and 2460 deletions

View File

@ -17,3 +17,4 @@ GTAGS
.ycm_extra_conf.py*
fuzz/libFuzzer/*
fuzz/corpus
fuzz/out

View File

@ -1 +1 @@
6353ce63e18f
ee21c9892907

View File

@ -0,0 +1,27 @@
FROM aarch64/ubuntu:xenial-20161213
MAINTAINER Franziskus Kiefer <franziskuskiefer@gmail.com>
RUN useradd -d /home/worker -s /bin/bash -m worker
WORKDIR /home/worker
# Add build and test scripts.
ADD bin /home/worker/bin
RUN chmod +x /home/worker/bin/*
# Install dependencies.
ADD setup.sh /tmp/setup.sh
RUN bash /tmp/setup.sh
# Env variables.
ENV HOME /home/worker
ENV SHELL /bin/bash
ENV USER worker
ENV LOGNAME worker
ENV HOSTNAME taskcluster-worker
ENV LANG en_US.UTF-8
ENV LC_ALL en_US.UTF-8
ENV HOST localhost
ENV DOMSUF localdomain
# Set a default command for debugging.
CMD ["/bin/bash", "--login"]

View File

@ -0,0 +1,20 @@
#!/usr/bin/env bash
set -v -e -x
if [ $(id -u) = 0 ]; then
# Drop privileges by re-running this script.
exec su worker $0
fi
# Default values for testing.
REVISION=${NSS_HEAD_REVISION:-default}
REPOSITORY=${NSS_HEAD_REPOSITORY:-https://hg.mozilla.org/projects/nss}
# Clone NSS.
for i in 0 2 5; do
sleep $i
hg clone -r $REVISION $REPOSITORY nss && exit 0
rm -rf nss
done
exit 1

View File

@ -0,0 +1,31 @@
#!/usr/bin/env bash
set -v -e -x
export DEBIAN_FRONTEND=noninteractive
# Update.
apt-get -y update
apt-get -y dist-upgrade
apt_packages=()
apt_packages+=('build-essential')
apt_packages+=('ca-certificates')
apt_packages+=('curl')
apt_packages+=('zlib1g-dev')
apt_packages+=('gyp')
apt_packages+=('ninja-build')
apt_packages+=('mercurial')
# Install packages.
apt-get install -y --no-install-recommends ${apt_packages[@]}
locale-gen en_US.UTF-8
dpkg-reconfigure locales
# Cleanup.
rm -rf ~/.ccache ~/.cache
apt-get autoremove -y
apt-get clean
apt-get autoclean
rm $0

View File

@ -12,6 +12,9 @@ RUN chmod +x /home/worker/bin/*
ADD setup.sh /tmp/setup.sh
RUN bash /tmp/setup.sh
# Change user.
USER worker
# Env variables.
ENV HOME /home/worker
ENV SHELL /bin/bash
@ -23,5 +26,8 @@ ENV LC_ALL en_US.UTF-8
ENV HOST localhost
ENV DOMSUF localdomain
# LLVM 4.0
ENV PATH "${PATH}:/home/worker/third_party/llvm-build/Release+Asserts/bin/"
# Set a default command for debugging.
CMD ["/bin/bash", "--login"]

View File

@ -19,9 +19,6 @@ apt_packages+=('ninja-build')
apt_packages+=('pkg-config')
apt_packages+=('zlib1g-dev')
# ct-verif and sanitizers
apt_packages+=('valgrind')
# Latest Mercurial.
apt_packages+=('mercurial')
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 41BD8711B1F0EC2B0D85B91CF59CE3A8323293EE
@ -38,11 +35,6 @@ git -C clang-tmp/clang checkout HEAD scripts/update.py
clang-tmp/clang/scripts/update.py
rm -fr clang-tmp
# Link to LLVM binaries.
for b in clang clang++ llvm-symbolizer; do
ln -s /home/worker/third_party/llvm-build/Release+Asserts/bin/$b /usr/local/bin/$b
done
locale-gen en_US.UTF-8
dpkg-reconfigure locales

View File

@ -12,6 +12,9 @@ RUN chmod +x /home/worker/bin/*
ADD setup.sh /tmp/setup.sh
RUN bash /tmp/setup.sh
# Change user.
USER worker
# Env variables.
ENV HOME /home/worker
ENV SHELL /bin/bash
@ -23,5 +26,8 @@ ENV LC_ALL en_US.UTF-8
ENV HOST localhost
ENV DOMSUF localdomain
# Rust + Go
ENV PATH "${PATH}:/home/worker/.cargo/bin/:/usr/lib/go-1.6/bin"
# Set a default command for debugging.
CMD ["/bin/bash", "--login"]

View File

@ -49,7 +49,11 @@ apt-get install -y --no-install-recommends ${apt_packages[@]}
ln -s /usr/include/x86_64-linux-gnu/zconf.h /usr/include
# Install clang-3.9 into /usr/local/.
curl http://llvm.org/releases/3.9.0/clang+llvm-3.9.0-x86_64-linux-gnu-ubuntu-16.04.tar.xz | tar xJv -C /usr/local --strip-components=1
# FIXME: verify signature
curl -L http://releases.llvm.org/3.9.0/clang+llvm-3.9.0-x86_64-linux-gnu-ubuntu-16.04.tar.xz | tar xJv -C /usr/local --strip-components=1
# Install latest Rust (stable).
su worker -c "curl https://sh.rustup.rs -sSf | sh -s -- -y"
locale-gen en_US.UTF-8
dpkg-reconfigure locales

View File

@ -30,18 +30,23 @@ queue.filter(task => {
}
}
if (task.tests == "bogo") {
// No BoGo tests on Windows.
if (task.tests == "bogo" || task.tests == "interop") {
// No windows
if (task.platform == "windows2012-64") {
return false;
}
// No BoGo tests on ARM.
// No ARM
if (task.collection == "arm-debug") {
return false;
}
}
// Temporarily disable SSL tests on ARM.
if (task.tests == "ssl" && task.collection == "arm-debug") {
return false;
}
// GYP builds with -Ddisable_libpkix=1 by default.
if ((task.collection == "gyp" || task.collection == "gyp-asan") &&
task.tests == "chains") {
@ -280,7 +285,7 @@ async function scheduleFuzzing() {
"/bin/bash",
"-c",
"bin/checkout.sh && " +
"nss/automation/taskcluster/scripts/build_gyp.sh -g -v --fuzz"
"nss/automation/taskcluster/scripts/build_gyp.sh -g -v --fuzz=tls"
],
artifacts: {
public: {
@ -316,31 +321,16 @@ async function scheduleFuzzing() {
queue.scheduleTask(merge(base, {
parent: task_build,
name: "Cert",
name: "QuickDER",
command: [
"/bin/bash",
"-c",
"bin/checkout.sh && nss/automation/taskcluster/scripts/fuzz.sh " +
"cert nss/fuzz/corpus/cert -max_total_time=300"
"quickder nss/fuzz/corpus/quickder -max_total_time=300"
],
// Need a privileged docker container to remove this.
env: {ASAN_OPTIONS: "detect_leaks=0"},
symbol: "SCert",
kind: "test"
}));
queue.scheduleTask(merge(base, {
parent: task_build,
name: "SPKI",
command: [
"/bin/bash",
"-c",
"bin/checkout.sh && nss/automation/taskcluster/scripts/fuzz.sh " +
"spki nss/fuzz/corpus/spki -max_total_time=300"
],
// Need a privileged docker container to remove this.
env: {ASAN_OPTIONS: "detect_leaks=0"},
symbol: "SPKI",
symbol: "QuickDER",
kind: "test"
}));
@ -363,7 +353,7 @@ async function scheduleTestBuilds() {
"/bin/bash",
"-c",
"bin/checkout.sh && " +
"nss/automation/taskcluster/scripts/build_gyp.sh -g -v --test"
"nss/automation/taskcluster/scripts/build_gyp.sh -g -v --test --ct-verif"
],
artifacts: {
public: {
@ -471,6 +461,9 @@ function scheduleTests(task_build, task_cert, test_base) {
queue.scheduleTask(merge(no_cert_base, {
name: "Bogo tests", symbol: "Bogo", tests: "bogo", cycle: "standard"
}));
queue.scheduleTask(merge(no_cert_base, {
name: "Interop tests", symbol: "Interop", tests: "interop", cycle: "standard"
}));
queue.scheduleTask(merge(no_cert_base, {
name: "Chains tests", symbol: "Chains", tests: "chains"
}));

View File

@ -34,7 +34,7 @@ function parseOptions(opts) {
// Parse unit tests.
let aliases = {"gtests": "gtest"};
let allUnitTests = ["bogo", "crmf", "chains", "cipher", "db", "ec", "fips",
"gtest", "lowhash", "merge", "sdr", "smime", "tools",
"gtest", "interop", "lowhash", "merge", "sdr", "smime", "tools",
"ssl", "mpi", "scert", "spki"];
let unittests = intersect(opts.unittests.split(/\s*,\s*/).map(t => {
return aliases[t] || t;

View File

@ -1,14 +1,9 @@
#!/usr/bin/env bash
source $(dirname $0)/tools.sh
if [[ $(id -u) -eq 0 ]]; then
# Drop privileges by re-running this script.
exec su worker $0
fi
source $(dirname "$0")/tools.sh
# Clone NSPR if needed.
hg_clone https://hg.mozilla.org/projects/nspr nspr default
hg_clone https://hg.mozilla.org/projects/nspr ./nspr default
# Build.
make -C nss nss_build_all

View File

@ -1,17 +1,12 @@
#!/usr/bin/env bash
source $(dirname $0)/tools.sh
if [[ $(id -u) -eq 0 ]]; then
# Drop privileges by re-running this script.
exec su worker -c "$0 $*"
fi
source $(dirname "$0")/tools.sh
# Clone NSPR if needed.
hg_clone https://hg.mozilla.org/projects/nspr nspr default
hg_clone https://hg.mozilla.org/projects/nspr ./nspr default
# Build.
nss/build.sh ${*--g -v}
nss/build.sh -g -v "$@"
# Package.
mkdir artifacts

View File

@ -1,11 +1,6 @@
#!/usr/bin/env bash
set -v -e -x
if [ $(id -u) = 0 ]; then
# Drop privileges by re-running this script.
exec su worker $0
fi
source $(dirname "$0")/tools.sh
mkdir -p /home/worker/artifacts

View File

@ -1,11 +1,9 @@
#!/usr/bin/env bash
source $(dirname $0)/tools.sh
source $(dirname "$0")/tools.sh
if [ $(id -u) = 0 ]; then
# Drop privileges by re-running this script.
exec su worker -c "$0 $*"
fi
type="$1"
shift
# Fetch artifact if needed.
fetch_dist
@ -13,8 +11,11 @@ fetch_dist
# Clone corpus.
./nss/fuzz/clone_corpus.sh
# Ensure we have a directory.
mkdir -p nss/fuzz/corpus/$type
# Fetch objdir name.
objdir=$(cat dist/latest)
# Run nssfuzz.
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:dist/$objdir/lib dist/$objdir/bin/nssfuzz $*
dist/$objdir/bin/nssfuzz-"$type" "$@"

View File

@ -1,16 +1,6 @@
#!/usr/bin/env bash
set -v -e -x
source $(dirname $0)/tools.sh
if [ $(id -u) = 0 ]; then
# Stupid Docker.
echo "127.0.0.1 localhost.localdomain" >> /etc/hosts
# Drop privileges by re-running this script.
exec su worker $0
fi
source $(dirname "$0")/tools.sh
# Fetch artifact if needed.
fetch_dist

View File

@ -1,11 +1,6 @@
#!/usr/bin/env bash
set -v -e -x
if [ $(id -u) -eq 0 ]; then
# Drop privileges by re-running this script.
exec su worker $0 "$@"
fi
source $(dirname "$0")/tools.sh
# Apply clang-format on the provided folder and verify that this doesn't change any file.
# If any file differs after formatting, the script eventually exits with 1.
@ -46,6 +41,7 @@ else
"$top/gtests/pk11_gtest" \
"$top/gtests/ssl_gtest" \
"$top/gtests/util_gtest" \
"$top/nss-tool" \
)
fi

View File

@ -1,15 +1,10 @@
#!/usr/bin/env bash
source $(dirname $0)/tools.sh
if [ $(id -u) = 0 ]; then
# Drop privileges by re-running this script.
exec su worker $0 $@
fi
source $(dirname "$0")/tools.sh
# Clone NSPR if needed.
if [ ! -d "nspr" ]; then
hg_clone https://hg.mozilla.org/projects/nspr nspr default
hg_clone https://hg.mozilla.org/projects/nspr ./nspr default
fi
# Build.

View File

@ -1,14 +1,6 @@
#!/usr/bin/env bash
source $(dirname $0)/tools.sh
if [ $(id -u) = 0 ]; then
# Stupid Docker.
echo "127.0.0.1 localhost.localdomain" >> /etc/hosts
# Drop privileges by re-running this script.
exec su worker $0
fi
source $(dirname "$0")/tools.sh
# Fetch artifact if needed.
fetch_dist

View File

@ -2,11 +2,21 @@
set -v -e -x
if [[ $(id -u) -eq 0 ]]; then
# Drop privileges by re-running this script.
# Note: this mangles arguments, better to avoid running scripts as root.
exec su worker -c "$0 $*"
fi
# Usage: hg_clone repo dir [revision=@]
hg_clone() {
repo=$1
dir=$2
rev=${3:-@}
if [ -d "$dir" ]; then
hg pull -R "$dir" -ur "$rev" "$repo" && return
rm -rf "$dir"
fi
for i in 0 2 5; do
sleep $i
hg clone -r "$rev" "$repo" "$dir" && return

View File

@ -6,15 +6,18 @@
set -e
source $(dirname $0)/coreconf/nspr.sh
cwd=$(cd $(dirname $0); pwd -P)
source "$cwd"/coreconf/nspr.sh
source "$cwd"/coreconf/sanitizers.sh
# Usage info
show_help() {
cat << EOF
Usage: ${0##*/} [-hcgv] [-j <n>] [--test] [--fuzz] [--scan-build[=output]]
[-m32] [--opt|-o] [--asan] [--ubsan] [--sancov[=edge|bb|func|...]]
[--pprof] [--msan]
show_help()
{
cat << EOF
Usage: ${0##*/} [-hcv] [-j <n>] [--nspr] [--gyp|-g] [--opt|-o] [-m32]
[--test] [--pprof] [--scan-build[=output]] [--ct-verif]
[--asan] [--ubsan] [--msan] [--sancov[=edge|bb|func|...]]
[--disable-tests] [--fuzz[=tls|oss]]
This script builds NSS with gyp and ninja.
@ -23,27 +26,44 @@ the features or platforms that NSS supports.
NSS build tool options:
-h display this help and exit
-c clean before build
-g force a rebuild of gyp (and NSPR, because why not)
-j <n> run at most <n> concurrent jobs
-v verbose build
-m32 do a 32-bit build on a 64-bit system
--test ignore map files and export everything we have
--fuzz enable fuzzing mode. this always enables test builds
--scan-build run the build with scan-build (scan-build has to be in the path)
--scan-build=/out/path sets the output path for scan-build
--opt|-o do an opt build
--asan do an asan build
--ubsan do an ubsan build
--ubsan=bool,shift,... sets specific UB sanitizers
--msan do an msan build
--sancov do sanitize coverage builds
--sancov=func sets coverage to function level for example
--pprof build with gperftool support
-h display this help and exit
-c clean before build
-v verbose build
-j <n> run at most <n> concurrent jobs
--nspr force a rebuild of NSPR
--gyp|-g force a rerun of gyp
--opt|-o do an opt build
-m32 do a 32-bit build on a 64-bit system
--test ignore map files and export everything we have
--fuzz build fuzzing targets (this always enables test builds)
--fuzz=tls to enable TLS fuzzing mode
--fuzz=oss to build for OSS-Fuzz
--pprof build with gperftool support
--ct-verif build with valgrind for ct-verif
--scan-build run the build with scan-build (scan-build has to be in the path)
--scan-build=/out/path sets the output path for scan-build
--asan do an asan build
--ubsan do an ubsan build
--ubsan=bool,shift,... sets specific UB sanitizers
--msan do an msan build
--sancov do sanitize coverage builds
--sancov=func sets coverage to function level for example
--disable-tests don't build tests and corresponding cmdline utils
EOF
}
run_verbose()
{
if [ "$verbose" = 1 ]; then
echo "$@"
exec 3>&1
else
exec 3>/dev/null
fi
"$@" 1>&3 2>&3
exec 3>&-
}
if [ -n "$CCC" ] && [ -z "$CXX" ]; then
export CXX="$CCC"
fi
@ -52,170 +72,159 @@ opt_build=0
build_64=0
clean=0
rebuild_gyp=0
rebuild_nspr=0
target=Debug
verbose=0
fuzz=0
ubsan_default=bool,signed-integer-overflow,shift,vptr
fuzz_tls=0
fuzz_oss=0
# parse parameters to store in config
params=$(echo "$*" | perl -pe 's/-c|-v|-g|-j [0-9]*|-h//g' | perl -pe 's/^\s*(.*?)\s*$/\1/')
params=$(echo "$params $CC $CCC" | tr " " "\n" | perl -pe 's/^\s*$//')
params=$(echo "${params[*]}" | sort)
cwd=$(cd $(dirname $0); pwd -P)
dist_dir="$cwd/../dist"
gyp_params=(--depth="$cwd" --generator-output=".")
nspr_params=()
ninja_params=()
# try to guess sensible defaults
arch=$(python "$cwd/coreconf/detect_host_arch.py")
arch=$(python "$cwd"/coreconf/detect_host_arch.py)
if [ "$arch" = "x64" -o "$arch" = "aarch64" ]; then
build_64=1
fi
gyp_params=()
ninja_params=()
scanbuild=()
sancov_default()
{
clang_version=$($CC --version | grep -oE 'clang version (3\.9\.|4\.)')
if [ -z "$clang_version" ]; then
echo "Need at least clang-3.9 (better 4.0) for sancov." 1>&2
exit 1
fi
if [ "$clang_version" = "clang version 3.9." ]; then
echo edge,indirect-calls,8bit-counters
else
echo trace-pc-guard
fi
}
enable_fuzz()
{
fuzz=1
nspr_sanitizer asan
nspr_sanitizer ubsan $ubsan_default
nspr_sanitizer sancov $(sancov_default)
gyp_params+=(-Duse_asan=1)
gyp_params+=(-Duse_ubsan=$ubsan_default)
gyp_params+=(-Duse_sancov=$(sancov_default))
# Adding debug symbols even for opt builds.
nspr_opt+=(--enable-debug-symbols)
}
# parse command line arguments
while [ $# -gt 0 ]; do
case $1 in
-c) clean=1 ;;
-g) rebuild_gyp=1 ;;
--gyp|-g) rebuild_gyp=1 ;;
--nspr) nspr_clean; rebuild_nspr=1 ;;
-j) ninja_params+=(-j "$2"); shift ;;
-v) ninja_params+=(-v); verbose=1 ;;
--test) gyp_params+=(-Dtest_build=1) ;;
--fuzz) gyp_params+=(-Dtest_build=1 -Dfuzz=1); enable_fuzz ;;
--scan-build) scanbuild=(scan-build) ;;
--scan-build=?*) scanbuild=(scan-build -o "${1#*=}") ;;
--fuzz) fuzz=1 ;;
--fuzz=oss) fuzz=1; fuzz_oss=1 ;;
--fuzz=tls) fuzz=1; fuzz_tls=1 ;;
--scan-build) enable_scanbuild ;;
--scan-build=?*) enable_scanbuild "${1#*=}" ;;
--opt|-o) opt_build=1 ;;
-m32|--m32) build_64=0 ;;
--asan) gyp_params+=(-Duse_asan=1); nspr_sanitizer asan ;;
--ubsan) gyp_params+=(-Duse_ubsan=$ubsan_default); nspr_sanitizer ubsan $ubsan_default ;;
--ubsan=?*) gyp_params+=(-Duse_ubsan="${1#*=}"); nspr_sanitizer ubsan "${1#*=}" ;;
--sancov) gyp_params+=(-Duse_sancov=$(sancov_default)); nspr_sanitizer sancov $(sancov_default) ;;
--sancov=?*) gyp_params+=(-Duse_sancov="${1#*=}"); nspr_sanitizer sancov "${1#*=}" ;;
--asan) enable_sanitizer asan ;;
--msan) enable_sanitizer msan ;;
--ubsan) enable_ubsan ;;
--ubsan=?*) enable_ubsan "${1#*=}" ;;
--sancov) enable_sancov ;;
--sancov=?*) enable_sancov "${1#*=}" ;;
--pprof) gyp_params+=(-Duse_pprof=1) ;;
--msan) gyp_params+=(-Duse_msan=1); nspr_sanitizer msan ;;
*) show_help; exit ;;
--ct-verif) gyp_params+=(-Dct_verif=1) ;;
--disable-tests) gyp_params+=(-Ddisable_tests=1) ;;
--no-zdefs) gyp_params+=(-Dno_zdefs=1) ;;
*) show_help; exit 2 ;;
esac
shift
done
if [ "$opt_build" = "1" ]; then
if [ "$opt_build" = 1 ]; then
target=Release
nspr_opt+=(--disable-debug --enable-optimize)
else
target=Debug
fi
if [ "$build_64" == "1" ]; then
nspr_opt+=(--enable-64bit)
if [ "$build_64" = 1 ]; then
nspr_params+=(--enable-64bit)
else
gyp_params+=(-Dtarget_arch=ia32)
fi
# clone fuzzing stuff
if [ "$fuzz" = "1" ]; then
[ $verbose = 0 ] && exec 3>/dev/null || exec 3>&1
echo "[1/2] Cloning libFuzzer files ..."
$cwd/fuzz/clone_libfuzzer.sh 1>&3 2>&3
echo "[2/2] Cloning fuzzing corpus ..."
$cwd/fuzz/clone_corpus.sh 1>&3 2>&3
exec 3>&-
fi
# check if we have to rebuild gyp
if [ "$params" != "$(cat $cwd/out/config 2>/dev/null)" -o "$rebuild_gyp" == 1 -o "$clean" == 1 ]; then
rebuild_gyp=1
rm -rf "$cwd/../nspr/$target" # force NSPR to rebuild
if [ "$fuzz" = 1 ]; then
source "$cwd"/coreconf/fuzz.sh
fi
# set paths
target_dir="$cwd/out/$target"
# get the realpath of $dist_dir
dist_dir=$(mkdir -p $dist_dir; cd $dist_dir; pwd -P)
# get object directory
obj_dir="$dist_dir/$target"
gyp_params+=(-Dnss_dist_dir=$dist_dir)
gyp_params+=(-Dnss_dist_obj_dir=$obj_dir)
gyp_params+=(-Dnspr_lib_dir=$obj_dir/lib)
gyp_params+=(-Dnspr_include_dir=$obj_dir/include/nspr)
target_dir="$cwd"/out/$target
mkdir -p "$target_dir"
dist_dir="$cwd"/../dist
dist_dir=$(mkdir -p "$dist_dir"; cd "$dist_dir"; pwd -P)
gyp_params+=(-Dnss_dist_dir="$dist_dir")
# -c = clean first
if [ "$clean" = 1 ]; then
rm -rf "$cwd/out"
rm -rf "$cwd/../nspr/$target"
nspr_clean
rm -rf "$cwd"/out
rm -rf "$dist_dir"
fi
# This saves a canonical representation of arguments that we are passing to gyp
# or the NSPR build so that we can work out if a rebuild is needed.
# Caveat: This can fail for arguments that are position-dependent.
# e.g., "-e 2 -f 1" and "-e 1 -f 2" canonicalize the same.
check_config()
{
local newconf="$1".new oldconf="$1"
shift
mkdir -p $(dirname "$newconf")
echo CC="$CC" >"$newconf"
echo CCC="$CCC" >>"$newconf"
echo CXX="$CXX" >>"$newconf"
for i in "$@"; do echo $i; done | sort >>"$newconf"
# Note: The following diff fails if $oldconf isn't there as well, which
# happens if we don't have a previous successful build.
! diff -q "$newconf" "$oldconf" >/dev/null 2>&1
}
gyp_config="$cwd"/out/gyp_config
nspr_config="$cwd"/out/$target/nspr_config
# If we don't have a build directory make sure that we rebuild.
if [ ! -d "$target_dir" ]; then
rebuild_nspr=1
rebuild_gyp=1
elif [ ! -d "$dist_dir"/$target ]; then
rebuild_nspr=1
fi
# Update NSPR ${C,CXX,LD}FLAGS.
nspr_set_flags $sanitizer_flags
if check_config "$nspr_config" "${nspr_params[@]}" \
nspr_cflags="$nspr_cflags" \
nspr_cxxflags="$nspr_cxxflags" \
nspr_ldflags="$nspr_ldflags"; then
rebuild_nspr=1
fi
# Forward sanitizer flags.
if [ ! -z "$sanitizer_flags" ]; then
gyp_params+=(-Dsanitizer_flags="$sanitizer_flags")
fi
if check_config "$gyp_config" "${gyp_params[@]}"; then
rebuild_gyp=1
fi
# save the chosen target
mkdir -p $dist_dir
echo $target > $dist_dir/latest
mkdir -p "$dist_dir"
echo $target > "$dist_dir"/latest
# pass on CC and CCC
if [ "${#scanbuild[@]}" -gt 0 ]; then
if [ -n "$CC" ]; then
scanbuild+=(--use-cc="$CC")
fi
if [ -n "$CCC" ]; then
scanbuild+=(--use-c++="$CCC")
fi
fi
if [ "$rebuild_nspr" = 1 ]; then
nspr_build "${nspr_params[@]}"
mv -f "$nspr_config".new "$nspr_config"
fi
if [ "$rebuild_gyp" = 1 ]; then
# These steps can take a while, so don't overdo them.
# Force a redo with -g.
if [ "$rebuild_gyp" = 1 -o ! -d "$target_dir" ]; then
build_nspr $verbose
# These extra arguments aren't used in determining whether to rebuild.
obj_dir="$dist_dir"/$target
gyp_params+=(-Dnss_dist_obj_dir=$obj_dir)
gyp_params+=(-Dnspr_lib_dir=$obj_dir/lib)
gyp_params+=(-Dnspr_include_dir=$obj_dir/include/nspr)
# Run gyp.
[ $verbose = 1 ] && set -v -x
"${scanbuild[@]}" gyp -f ninja "${gyp_params[@]}" --depth="$cwd" \
--generator-output="." "$cwd/nss.gyp"
[ $verbose = 1 ] && set +v +x
run_verbose run_scanbuild gyp -f ninja "${gyp_params[@]}" "$cwd"/nss.gyp
# Store used parameters for next run.
echo "$params" > "$cwd/out/config"
mv -f "$gyp_config".new "$gyp_config"
fi
# Run ninja.
if which ninja >/dev/null 2>&1; then
ninja=(ninja)
elif which ninja-build >/dev/null 2>&1; then
ninja=(ninja-build)
if hash ninja 2>/dev/null; then
ninja=ninja
elif hash ninja-build 2>/dev/null; then
ninja=ninja-build
else
echo "Please install ninja" 1>&2
exit 1
fi
"${scanbuild[@]}" $ninja -C "$target_dir" "${ninja_params[@]}"
run_scanbuild $ninja -C "$target_dir" "${ninja_params[@]}"

View File

@ -32,8 +32,6 @@
'<(DEPTH)/lib/dev/dev.gyp:nssdev',
'<(DEPTH)/lib/base/base.gyp:nssb',
'<(DEPTH)/lib/freebl/freebl.gyp:freebl',
'<(DEPTH)/lib/pk11wrap/pk11wrap.gyp:pk11wrap',
'<(DEPTH)/lib/certhigh/certhigh.gyp:certhi',
'<(DEPTH)/lib/sqlite/sqlite.gyp:sqlite3',
],
'conditions': [

View File

@ -52,7 +52,6 @@
'use_system_zlib%': 1,
'nspr_libs%': ['-lplds4', '-lplc4', '-lnspr4'],
'zlib_libs%': ['-lz'],
'optimize_flags%': '-O2',
'dll_prefix': 'lib',
'conditions': [
['OS=="mac"', {
@ -98,14 +97,14 @@
'moz_fold_libs%': 0,
'moz_folded_library_name%': '',
'ssl_enable_zlib%': 1,
'use_asan%': 0,
'use_ubsan%': 0,
'use_msan%': 0,
'use_sancov%': 0,
'sanitizer_flags%': 0,
'test_build%': 0,
'no_zdefs%': 0,
'fuzz%': 0,
'fuzz_tls%': 0,
'sign_libs%': 1,
'use_pprof%': 0,
'ct_verif%': 0,
'nss_public_dist_dir%': '<(nss_dist_dir)/public',
'nss_private_dist_dir%': '<(nss_dist_dir)/private',
},
@ -115,6 +114,8 @@
'variables': {
'mapfile%': '',
'test_build%': 0,
'debug_optimization_level%': '0',
'release_optimization_level%': '2',
},
'standalone_static_library': 0,
'include_dirs': [
@ -133,6 +134,11 @@
'-lc',
],
}],
[ 'fuzz==1', {
'variables': {
'debug_optimization_level%': '1',
},
}],
],
'target_conditions': [
# If we want to properly export a static library, and copy it to lib,
@ -209,7 +215,6 @@
[ 'cc_use_gnu_ld==1', {
'ldflags': [
'-Wl,--gc-sections',
'-Wl,-z,defs',
],
'conditions': [
['OS=="dragonfly" or OS=="freebsd" or OS=="netbsd" or OS=="openbsd"', {
@ -218,6 +223,11 @@
'-Wl,--warn-unresolved-symbols',
],
}],
['no_zdefs==0', {
'ldflags': [
'-Wl,-z,defs',
],
}],
],
}],
],
@ -341,79 +351,22 @@
'<!@(<(python) <(DEPTH)/coreconf/werror.py)',
],
}],
[ 'fuzz==1', {
[ 'fuzz_tls==1', {
'cflags': [
'-Wno-unused-function',
]
],
}],
[ 'fuzz==1 or use_asan==1 or use_ubsan!=0', {
'cflags': ['-O1'],
[ 'sanitizer_flags!=0', {
'cflags': ['<@(sanitizer_flags)'],
'ldflags': ['<@(sanitizer_flags)'],
'xcode_settings': {
'GCC_OPTIMIZATION_LEVEL': '1', # -O1
}
}],
[ 'use_asan==1', {
'variables': {
'asan_flags': '<!(<(python) <(DEPTH)/coreconf/sanitizers.py asan)',
'no_ldflags': '<!(<(python) <(DEPTH)/coreconf/sanitizers.py ld)',
},
'cflags': ['<@(asan_flags)'],
'ldflags': ['<@(asan_flags)'],
'ldflags!': ['<@(no_ldflags)'],
'xcode_settings': {
'OTHER_CFLAGS': ['<@(asan_flags)'],
'OTHER_LDFLAGS!': ['<@(no_ldflags)'],
'OTHER_CFLAGS': ['<@(sanitizer_flags)'],
# We want to pass -fsanitize=... to our final link call,
# but not to libtool. OTHER_LDFLAGS is passed to both.
# To trick GYP into doing what we want, we'll piggyback on
# LIBRARY_SEARCH_PATHS, producing "-L/usr/lib -fsanitize=...".
# The -L/usr/lib is redundant but innocuous: it's a default path.
'LIBRARY_SEARCH_PATHS': ['/usr/lib <(asan_flags)'],
},
}],
[ 'use_ubsan!=0', {
'variables': {
'ubsan_flags': '<!(<(python) <(DEPTH)/coreconf/sanitizers.py ubsan <(use_ubsan))',
'no_ldflags': '<!(<(python) <(DEPTH)/coreconf/sanitizers.py ld)',
},
'cflags': ['<@(ubsan_flags)'],
'ldflags': ['<@(ubsan_flags)'],
'ldflags!': ['<@(no_ldflags)'],
'xcode_settings': {
'OTHER_CFLAGS': ['<@(ubsan_flags)'],
'OTHER_LDFLAGS!': ['<@(no_ldflags)'],
# See comment above.
'LIBRARY_SEARCH_PATHS': ['/usr/lib <(ubsan_flags)'],
},
}],
[ 'use_msan==1', {
'variables': {
'msan_flags': '<!(<(python) <(DEPTH)/coreconf/sanitizers.py msan)',
'no_ldflags': '<!(<(python) <(DEPTH)/coreconf/sanitizers.py ld)',
},
'cflags': ['<@(msan_flags)'],
'ldflags': ['<@(msan_flags)'],
'ldflags!': ['<@(no_ldflags)'],
'xcode_settings': {
'OTHER_CFLAGS': ['<@(msan_flags)'],
'OTHER_LDFLAGS!': ['<@(no_ldflags)'],
# See comment above.
'LIBRARY_SEARCH_PATHS': ['/usr/lib <(msan_flags)'],
},
}],
[ 'use_sancov!=0', {
'variables': {
'sancov_flags': '<!(<(python) <(DEPTH)/coreconf/sanitizers.py sancov <(use_sancov))',
'no_ldflags': '<!(<(python) <(DEPTH)/coreconf/sanitizers.py ld)',
},
'cflags': ['<@(sancov_flags)'],
'ldflags': ['<@(sancov_flags)'],
'ldflags!': ['<@(no_ldflags)'],
'xcode_settings': {
'OTHER_CFLAGS': ['<@(sancov_flags)'],
'OTHER_LDFLAGS!': ['<@(no_ldflags)'],
# See comment above.
'LIBRARY_SEARCH_PATHS': ['/usr/lib <(sancov_flags)'],
'LIBRARY_SEARCH_PATHS': ['/usr/lib <(sanitizer_flags)'],
},
}],
[ 'OS=="android" and mozilla_client==0', {
@ -472,7 +425,6 @@
],
},
},
}],
[ 'target_arch=="x64"', {
'msvs_configuration_platform': 'x64',
@ -515,14 +467,15 @@
],
#TODO: DEBUG_$USER
'defines': ['DEBUG'],
'cflags': [ '-O<(debug_optimization_level)' ],
'xcode_settings': {
'COPY_PHASE_STRIP': 'NO',
'GCC_OPTIMIZATION_LEVEL': '0',
'GCC_OPTIMIZATION_LEVEL': '<(debug_optimization_level)',
'GCC_GENERATE_DEBUGGING_SYMBOLS': 'YES',
},
'msvs_settings': {
'VCCLCompilerTool': {
'Optimization': '0',
'Optimization': '<(debug_optimization_level)',
'BasicRuntimeChecks': '3',
'RuntimeLibrary': '2', # /MD
},
@ -537,16 +490,15 @@
# Common settings for release should go here.
'Release': {
'inherit_from': ['Common'],
'defines': [
'NDEBUG',
],
'defines': ['NDEBUG'],
'cflags': [ '-O<(release_optimization_level)' ],
'xcode_settings': {
'DEAD_CODE_STRIPPING': 'YES', # -Wl,-dead_strip
'GCC_OPTIMIZATION_LEVEL': '2', # -O2
'GCC_OPTIMIZATION_LEVEL': '<(release_optimization_level)',
},
'msvs_settings': {
'VCCLCompilerTool': {
'Optimization': '2', # /Os
'Optimization': '<(release_optimization_level)',
'RuntimeLibrary': '2', # /MD
},
'VCLinkerTool': {

View File

@ -10,3 +10,4 @@
*/
#error "Do not include this header file."

View File

@ -0,0 +1,38 @@
#!/usr/bin/env bash
# This file is used by build.sh to setup fuzzing.
set +e
# Default to clang if CC is not set.
if [ -z "$CC" ]; then
command -v clang &> /dev/null 2>&1
if [ $? != 0 ]; then
echo "Fuzzing requires clang!"
exit 1
fi
export CC=clang
export CCC=clang++
export CXX=clang++
fi
gyp_params+=(-Dtest_build=1 -Dfuzz=1)
# Add debug symbols even for opt builds.
nspr_params+=(--enable-debug-symbols)
if [ "$fuzz_oss" = 1 ]; then
gyp_params+=(-Dno_zdefs=1)
else
enable_sanitizer asan
enable_ubsan
enable_sancov
fi
if [ "$fuzz_tls" = 1 ]; then
gyp_params+=(-Dfuzz_tls=1)
fi
if [ ! -f "/usr/lib/libFuzzingEngine.a" ]; then
echo "Cloning libFuzzer files ..."
run_verbose "$cwd"/fuzz/clone_libfuzzer.sh
fi

View File

@ -5,7 +5,6 @@
# the features or platforms that the regular NSPR build supports.
# variables
nspr_opt=()
nspr_cflags=
nspr_cxxflags=
nspr_ldflags=
@ -15,39 +14,38 @@ if hash gmake 2>/dev/null; then
make() { command gmake "$@"; }
fi
nspr_sanitizer()
nspr_set_flags()
{
nspr_cflags="$nspr_cflags $(python $cwd/coreconf/sanitizers.py $1 $2)"
nspr_cxxflags="$nspr_cxxflags $(python $cwd/coreconf/sanitizers.py $1 $2)"
nspr_ldflags="$nspr_ldflags $(python $cwd/coreconf/sanitizers.py $1 $2)"
nspr_cflags="$CFLAGS $@"
nspr_cxxflags="$CXXFLAGS $@"
nspr_ldflags="$LDFLAGS $@"
}
verbose()
nspr_build()
{
CFLAGS=$nspr_cflags CXXFLAGS=$nspr_cxxflags LDFLAGS=$nspr_ldflags \
CC=$CC CXX=$CCC ../configure "${nspr_opt[@]}" --prefix="$obj_dir"
make -C "$cwd/../nspr/$target"
make -C "$cwd/../nspr/$target" install
}
local nspr_dir="$cwd"/../nspr/$target
mkdir -p "$nspr_dir"
silent()
{
echo "[1/3] configure NSPR ..."
CFLAGS=$nspr_cflags CXXFLAGS=$nspr_cxxflags LDFLAGS=$nspr_ldflags \
CC=$CC CXX=$CCC ../configure "${nspr_opt[@]}" --prefix="$obj_dir" 1> /dev/null
echo "[2/3] make NSPR ..."
make -C "$cwd/../nspr/$target" 1> /dev/null
echo "[3/3] install NSPR ..."
make -C "$cwd/../nspr/$target" install 1> /dev/null
}
build_nspr()
{
mkdir -p "$cwd/../nspr/$target"
cd "$cwd/../nspr/$target"
if [ "$1" == 1 ]; then
verbose
else
silent
# These NSPR options are directory-specific, so they don't need to be
# included in nspr_opt and changing them doesn't force a rebuild of NSPR.
extra_params=(--prefix="$dist_dir"/$target)
if [ "$opt_build" = 1 ]; then
extra_params+=(--disable-debug --enable-optimize)
fi
echo "NSPR [1/3] configure ..."
pushd "$nspr_dir" >/dev/null
CFLAGS="$nspr_cflags" CXXFLAGS="$nspr_cxxflags" \
LDFLAGS="$nspr_ldflags" CC="$CC" CXX="$CCC" \
run_verbose ../configure "${extra_params[@]}" "$@"
popd >/dev/null
echo "NSPR [2/3] make ..."
run_verbose make -C "$nspr_dir"
echo "NSPR [3/3] install ..."
run_verbose make -C "$nspr_dir" install
}
nspr_clean()
{
rm -rf "$cwd"/../nspr/$target
}

View File

@ -5,7 +5,7 @@ import sys
def main():
if len(sys.argv) < 2:
raise Exception('Specify either "ld", asan", "msan", "sancov" or "ubsan" as argument.')
raise Exception('Specify either "asan", "msan", "sancov" or "ubsan" as argument.')
sanitizer = sys.argv[1]
if sanitizer == "ubsan":
@ -27,12 +27,7 @@ def main():
print('-fsanitize-coverage='+sys.argv[2]+' ', end='')
return
# We have to remove this from the ld flags when building asan.
if sanitizer == "ld":
print('-Wl,-z,defs ', end='')
return
raise Exception('Specify either "ld", asan", "msan", "sancov" or "ubsan" as argument.')
raise Exception('Specify either "asan", "msan", "sancov" or "ubsan" as argument.')
if __name__ == '__main__':
main()

View File

@ -0,0 +1,74 @@
#!/usr/bin/env bash
# This file is used by build.sh to setup sanitizers.
sanitizer_flags=""
# This tracks what sanitizers are enabled, and their options.
declare -A sanitizers
enable_sanitizer()
{
local san="$1"
[ -n "${sanitizers[$san]}" ] && return
sanitizers[$san]="${2:-1}"
if [ -z "$sanitizer_flags" ]; then
gyp_params+=(-Dno_zdefs=1)
fi
local cflags=$(python $cwd/coreconf/sanitizers.py "$@")
sanitizer_flags="$sanitizer_flags $cflags"
}
enable_sancov()
{
local clang_version=$($CC --version | grep -oE 'clang version (3\.9\.|4\.)')
if [ -z "$clang_version" ]; then
echo "Need at least clang-3.9 (better 4.0) for sancov." 1>&2
exit 1
fi
local sancov
if [ -n "$1" ]; then
sancov="$1"
elif [ "$clang_version" = "clang version 3.9." ]; then
sancov=edge,indirect-calls,8bit-counters
else
sancov=trace-pc-guard,trace-cmp
fi
enable_sanitizer sancov "$sancov"
}
enable_ubsan()
{
local ubsan
if [ -n "$1" ]; then
ubsan="$1"
else
ubsan=bool,signed-integer-overflow,shift,vptr
fi
enable_sanitizer ubsan "$ubsan"
}
# Not strictly a sanitizer, but the pattern fits
scanbuild=()
enable_scanbuild()
{
[ "${#scanbuild[@]}" -gt 0 ] && return
scanbuild=(scan-build)
if [ -n "$1" ]; then
scanbuild+=(-o "$1")
fi
# pass on CC and CCC to scanbuild
if [ -n "$CC" ]; then
scanbuild+=(--use-cc="$CC")
fi
if [ -n "$CCC" ]; then
scanbuild+=(--use-c++="$CCC")
fi
}
run_scanbuild()
{
"${scanbuild[@]}" "$@"
}

View File

@ -0,0 +1,17 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "FuzzerInternal.h"
#include "asn1_mutators.h"
#include "shared.h"
extern const uint16_t DEFAULT_MAX_LENGTH = 3072U;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
CERTCertificate cert;
QuickDERDecode(&cert, SEC_SignedCertificateTemplate, Data, Size);
return 0;
}
ADD_CUSTOM_MUTATORS({&ASN1MutatorFlipConstructed, &ASN1MutatorChangeType})

View File

@ -1,22 +1,46 @@
#!/bin/sh
d=$(dirname $0)
$d/git-copy.sh https://chromium.googlesource.com/chromium/llvm-project/llvm/lib/Fuzzer 1b543d6e5073b56be214394890c9193979a3d7e1 $d/libFuzzer
$d/git-copy.sh https://chromium.googlesource.com/chromium/llvm-project/llvm/lib/Fuzzer 33c20f597a2e312611d52677ff0fdd9335b485b7 $d/libFuzzer
# [https://llvm.org/bugs/show_bug.cgi?id=31318]
# This prevents a known buffer overrun that won't be fixed as the affected code
# will go away in the near future. Until that is we have to patch it as we seem
# to constantly run into it.
cat <<EOF | patch -p0 -d $d
diff --git libFuzzer/FuzzerMutate.cpp libFuzzer/FuzzerMutate.cpp
--- libFuzzer/FuzzerMutate.cpp
+++ libFuzzer/FuzzerMutate.cpp
@@ -53,10 +53,9 @@
DefaultMutators.push_back(
{&MutationDispatcher::Mutate_AddWordFromTORC, "CMP"});
diff --git libFuzzer/FuzzerLoop.cpp libFuzzer/FuzzerLoop.cpp
--- libFuzzer/FuzzerLoop.cpp
+++ libFuzzer/FuzzerLoop.cpp
@@ -472,6 +472,9 @@
uint8_t dummy;
ExecuteCallback(&dummy, 0);
+ Mutators = DefaultMutators;
if (EF->LLVMFuzzerCustomMutator)
Mutators.push_back({&MutationDispatcher::Mutate_Custom, "Custom"});
- else
- Mutators = DefaultMutators;
if (EF->LLVMFuzzerCustomCrossOver)
Mutators.push_back(
+ // Number of counters might have changed.
+ PrepareCounters(&MaxCoverage);
+
for (const auto &U : *InitialCorpus) {
if (size_t NumFeatures = RunOne(U)) {
CheckExitOnSrcPosOrItem();
EOF
# Latest Libfuzzer uses __sanitizer_dump_coverage(), a symbol to be introduced
# with LLVM 4.0. To keep our code working with LLVM 3.x to simplify development
# of fuzzers we'll just provide it ourselves.
cat <<EOF | patch -p0 -d $d
diff --git libFuzzer/FuzzerTracePC.cpp libFuzzer/FuzzerTracePC.cpp
--- libFuzzer/FuzzerTracePC.cpp
+++ libFuzzer/FuzzerTracePC.cpp
@@ -24,6 +24,12 @@
#include <set>
#include <sstream>
+#if defined(__clang_major__) && (__clang_major__ == 3)
+void __sanitizer_dump_coverage(const uintptr_t *pcs, uintptr_t len) {
+ // SanCov in LLVM 4.x will provide this symbol. Make 3.x work.
+}
+#endif
+
namespace fuzzer {
TracePC TPC;
EOF

View File

@ -4,79 +4,134 @@
{
'includes': [
'../coreconf/config.gypi',
'../cmd/platlibs.gypi'
],
'variables': {
'use_fuzzing_engine': '<!(test -f /usr/lib/libFuzzingEngine.a && echo 1 || echo 0)',
},
'target_defaults': {
'variables': {
'debug_optimization_level': '2',
},
'target_conditions': [
[ '_type=="executable"', {
'libraries!': [
'<@(nspr_libs)',
],
'libraries': [
'<(nss_dist_obj_dir)/lib/libplds4.a',
'<(nss_dist_obj_dir)/lib/libnspr4.a',
'<(nss_dist_obj_dir)/lib/libplc4.a',
],
}],
],
},
'targets': [
{
'target_name': 'libFuzzer',
'type': 'static_library',
'sources': [
'libFuzzer/FuzzerCrossOver.cpp',
'libFuzzer/FuzzerDriver.cpp',
'libFuzzer/FuzzerExtFunctionsDlsym.cpp',
'libFuzzer/FuzzerExtFunctionsWeak.cpp',
'libFuzzer/FuzzerIO.cpp',
'libFuzzer/FuzzerLoop.cpp',
'libFuzzer/FuzzerMutate.cpp',
'libFuzzer/FuzzerSHA1.cpp',
'libFuzzer/FuzzerTracePC.cpp',
'libFuzzer/FuzzerTraceState.cpp',
'libFuzzer/FuzzerUtil.cpp',
'libFuzzer/FuzzerUtilDarwin.cpp',
'libFuzzer/FuzzerUtilLinux.cpp',
'target_name': 'fuzz_base',
'dependencies': [
'<(DEPTH)/lib/certdb/certdb.gyp:certdb',
'<(DEPTH)/lib/certhigh/certhigh.gyp:certhi',
'<(DEPTH)/lib/cryptohi/cryptohi.gyp:cryptohi',
'<(DEPTH)/lib/base/base.gyp:nssb',
'<(DEPTH)/lib/dev/dev.gyp:nssdev',
'<(DEPTH)/lib/pki/pki.gyp:nsspki',
'<(DEPTH)/lib/util/util.gyp:nssutil',
'<(DEPTH)/lib/nss/nss.gyp:nss_static',
'<(DEPTH)/lib/pk11wrap/pk11wrap.gyp:pk11wrap',
'<(DEPTH)/lib/pkcs7/pkcs7.gyp:pkcs7',
],
'cflags': [
'-O2',
'conditions': [
['use_fuzzing_engine==0', {
'type': 'static_library',
'sources': [
'libFuzzer/FuzzerCrossOver.cpp',
'libFuzzer/FuzzerDriver.cpp',
'libFuzzer/FuzzerExtFunctionsDlsym.cpp',
'libFuzzer/FuzzerExtFunctionsWeak.cpp',
'libFuzzer/FuzzerExtFunctionsWeakAlias.cpp',
'libFuzzer/FuzzerIO.cpp',
'libFuzzer/FuzzerIOPosix.cpp',
'libFuzzer/FuzzerIOWindows.cpp',
'libFuzzer/FuzzerLoop.cpp',
'libFuzzer/FuzzerMain.cpp',
'libFuzzer/FuzzerMerge.cpp',
'libFuzzer/FuzzerMutate.cpp',
'libFuzzer/FuzzerSHA1.cpp',
'libFuzzer/FuzzerTracePC.cpp',
'libFuzzer/FuzzerTraceState.cpp',
'libFuzzer/FuzzerUtil.cpp',
'libFuzzer/FuzzerUtilDarwin.cpp',
'libFuzzer/FuzzerUtilLinux.cpp',
'libFuzzer/FuzzerUtilPosix.cpp',
'libFuzzer/FuzzerUtilWindows.cpp',
],
'cflags/': [
['exclude', '-fsanitize-coverage'],
],
'xcode_settings': {
'OTHER_CFLAGS/': [
['exclude', '-fsanitize-coverage'],
],
},
'direct_dependent_settings': {
'include_dirs': [
'libFuzzer',
],
},
}, {
'type': 'none',
'direct_dependent_settings': {
'libraries': ['-lFuzzingEngine'],
}
}]
],
'cflags!': [
'-O1',
],
'cflags/': [
['exclude', '-fsanitize'],
],
'xcode_settings': {
'GCC_OPTIMIZATION_LEVEL': '2', # -O2
'OTHER_CFLAGS/': [
['exclude', '-fsanitize'],
],
},
},
{
'target_name': 'nssfuzz',
'target_name': 'nssfuzz-pkcs8',
'type': 'executable',
'sources': [
'asn1_mutators.cc',
'nssfuzz.cc',
'initialize.cc',
'pkcs8_target.cc',
'quickder_targets.cc',
],
'dependencies': [
'<(DEPTH)/exports.gyp:nss_exports',
'libFuzzer',
'fuzz_base',
],
'cflags': [
'-O2',
},
{
'target_name': 'nssfuzz-quickder',
'type': 'executable',
'sources': [
'asn1_mutators.cc',
'initialize.cc',
'quickder_target.cc',
],
'cflags!': [
'-O1',
'dependencies': [
'<(DEPTH)/exports.gyp:nss_exports',
'fuzz_base',
],
'cflags/': [
['exclude', '-fsanitize-coverage'],
},
{
'target_name': 'nssfuzz-hash',
'type': 'executable',
'sources': [
'hash_target.cc',
'initialize.cc',
],
'dependencies': [
'<(DEPTH)/exports.gyp:nss_exports',
'fuzz_base',
],
},
{
'target_name': 'nssfuzz',
'type': 'none',
'dependencies': [
'nssfuzz-hash',
'nssfuzz-pkcs8',
'nssfuzz-quickder',
],
'xcode_settings': {
'GCC_OPTIMIZATION_LEVEL': '2', # -O2
'OTHER_CFLAGS/': [
['exclude', '-fsanitize-coverage'],
],
},
}
],
'target_defaults': {
'include_dirs': [
'libFuzzer',
],
},
'variables': {
'module': 'nss',
}
}

View File

@ -0,0 +1,42 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <memory>
#include <vector>
#include "FuzzerInternal.h"
#include "hasht.h"
#include "pk11pub.h"
#include "secoidt.h"
#include "shared.h"
extern const uint16_t DEFAULT_MAX_LENGTH = 4096U;
const std::vector<SECOidTag> algos = {SEC_OID_MD5, SEC_OID_SHA1, SEC_OID_SHA256,
SEC_OID_SHA384, SEC_OID_SHA512};
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
uint8_t hashOut[HASH_LENGTH_MAX];
static std::unique_ptr<NSSDatabase> db(new NSSDatabase());
assert(db != nullptr);
// simple hashing.
for (auto algo : algos) {
assert(PK11_HashBuf(algo, hashOut, data, size) == SECSuccess);
}
// hashing with context.
for (auto algo : algos) {
unsigned int len = 0;
PK11Context *context = PK11_CreateDigestContext(algo);
assert(context != nullptr);
assert(PK11_DigestBegin(context) == SECSuccess);
assert(PK11_DigestFinal(context, hashOut, &len, HASH_LENGTH_MAX) ==
SECSuccess);
PK11_DestroyContext(context, PR_TRUE);
}
return 0;
}

View File

@ -0,0 +1,54 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <string.h>
#include <algorithm>
#include <iostream>
#include <vector>
#include "assert.h"
extern const uint16_t DEFAULT_MAX_LENGTH;
const uint16_t MERGE_MAX_LENGTH = 50000U;
extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) {
std::vector<std::string> args(*argv, *argv + *argc);
auto hasMaxLenArg = [](std::string &a) { return a.find("-max_len=") == 0; };
// Nothing to do if a max_len argument is given.
if (any_of(args.begin(), args.end(), hasMaxLenArg)) {
return 0;
}
auto hasMergeArg = [](std::string &a) { return a.find("-merge=1") == 0; };
uint16_t max_length = DEFAULT_MAX_LENGTH;
// Set specific max_len when merging.
if (any_of(args.begin(), args.end(), hasMergeArg)) {
max_length = MERGE_MAX_LENGTH;
}
std::cerr << "INFO: MaxLen: " << max_length << std::endl;
std::string param = "-max_len=" + std::to_string(max_length);
// Copy original arguments.
char **new_args = new char *[*argc + 1];
for (int i = 0; i < *argc; i++) {
new_args[i] = (*argv)[i];
}
// Append corpus max length.
size_t param_len = param.size() + 1;
new_args[*argc] = new char[param_len];
memcpy(new_args[*argc], param.c_str(), param_len);
// Update arguments.
(*argc)++;
*argv = new_args;
return 0;
}

View File

@ -1,163 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <iomanip>
#include <iostream>
#include "FuzzerInternal.h"
#include "FuzzerMutate.h"
#include "FuzzerRandom.h"
#include "registry.h"
#include "shared.h"
using namespace std;
static vector<Mutator> gMutators;
class Args {
public:
Args(int argc, char **argv) : args_(argv, argv + argc) {}
string &operator[](const int idx) { return args_[idx]; }
bool Has(const string &arg) {
return any_of(args_.begin(), args_.end(),
[&arg](string &a) { return a.find(arg) == 0; });
}
void Append(const string &arg) { args_.push_back(arg); }
void Remove(const int index) {
assert(index < count());
args_.erase(args_.begin() + index);
}
vector<char *> argv() {
vector<char *> out;
out.resize(count());
transform(args_.begin(), args_.end(), out.begin(),
[](string &a) { return const_cast<char *>(a.c_str()); });
return out;
}
size_t count() { return args_.size(); }
private:
vector<string> args_;
};
void printUsage(Args &args) {
size_t sep = args[0].rfind("/") + 1;
string progName = args[0].substr(sep);
cerr << progName << " - Various libFuzzer targets for NSS" << endl << endl;
cerr << "Usage: " << progName << " <target> <libFuzzer options>" << endl
<< endl;
cerr << "Valid targets:" << endl;
vector<string> names = Registry::Names();
// Find length of the longest name.
size_t name_w =
max_element(names.begin(), names.end(), [](string &a, string &b) {
return a.size() < b.size();
})->size();
// Find length of the longest description.
auto max = max_element(names.begin(), names.end(), [](string &a, string &b) {
return Registry::Desc(a).size() < Registry::Desc(b).size();
});
size_t desc_w = Registry::Desc(*max).size();
// Print list of targets.
for (string name : names) {
cerr << " " << left << setw(name_w) << name << " - " << setw(desc_w)
<< Registry::Desc(name)
<< " [default max_len=" << Registry::MaxLen(name) << "]" << endl;
}
// Some usage examples.
cerr << endl << "Run fuzzer with a given corpus directory:" << endl;
cerr << " " << progName << " <target> /path/to/corpus" << endl;
cerr << endl << "Run fuzzer with a single test input:" << endl;
cerr << " " << progName
<< " <target> ./crash-14d4355b971092e39572bc306a135ddf9f923e19" << endl;
cerr << endl
<< "Specify the number of cores you wish to dedicate to fuzzing:"
<< endl;
cerr << " " << progName << " <target> -jobs=8 -workers=8 /path/to/corpus"
<< endl;
cerr << endl << "Override the maximum length of a test input:" << endl;
cerr << " " << progName << " <target> -max_len=2048 /path/to/corpus" << endl;
cerr << endl
<< "Minimize a given corpus and put the result into 'new_corpus':"
<< endl;
cerr << " " << progName
<< " <target> -merge=1 -max_len=50000 ./new_corpus /path/to/corpus"
<< endl;
cerr << endl << "Merge new test inputs into a corpus:" << endl;
cerr
<< " " << progName
<< " <target> -merge=1 -max_len=50000 /path/to/corpus ./inputs1 ./inputs2"
<< endl;
cerr << endl << "Print libFuzzer usage information:" << endl;
cerr << " " << progName << " <target> -help=1" << endl << endl;
cerr << "Check out the docs at http://llvm.org/docs/LibFuzzer.html" << endl;
}
int main(int argc, char **argv) {
Args args(argc, argv);
if (args.count() < 2 || !Registry::Has(args[1])) {
printUsage(args);
return 1;
}
string targetName(args[1]);
// Add target mutators.
auto mutators = Registry::Mutators(targetName);
gMutators.insert(gMutators.end(), mutators.begin(), mutators.end());
// Remove the target argument when -workers=x or -jobs=y is NOT given.
// If both are given, libFuzzer will spawn multiple processes for the target.
if (!args.Has("-workers=") || !args.Has("-jobs=")) {
args.Remove(1);
}
// Set default max_len arg, if none given and we're not merging.
if (!args.Has("-max_len=") && !args.Has("-merge=1")) {
uint16_t maxLen = Registry::MaxLen(targetName);
args.Append("-max_len=" + to_string(maxLen));
}
// Hand control to the libFuzzer driver.
vector<char *> args_new(args.argv());
argc = args_new.size();
argv = args_new.data();
return fuzzer::FuzzerDriver(&argc, &argv, Registry::Func(targetName));
}
extern "C" size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
size_t MaxSize, unsigned int Seed) {
if (gMutators.empty()) {
return 0;
}
// Forward to a pseudorandom mutator.
fuzzer::Random R(Seed);
return gMutators.at(R(gMutators.size()))(Data, Size, MaxSize, Seed);
}

View File

@ -1,20 +1,21 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <assert.h>
#include <stdint.h>
#include <memory>
#include <vector>
#include "keyhi.h"
#include "pk11pub.h"
#include "registry.h"
#include "FuzzerInternal.h"
#include "asn1_mutators.h"
#include "assert.h"
#include "shared.h"
extern "C" int pkcs8_fuzzing_target(const uint8_t *Data, size_t Size) {
extern const uint16_t DEFAULT_MAX_LENGTH = 2048U;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
SECItem data = {siBuffer, (unsigned char *)Data, (unsigned int)Size};
static std::unique_ptr<NSSDatabase> db(new NSSDatabase());
@ -34,5 +35,4 @@ extern "C" int pkcs8_fuzzing_target(const uint8_t *Data, size_t Size) {
return 0;
}
REGISTER_FUZZING_TARGET("pkcs8", pkcs8_fuzzing_target, 2048, "PKCS#8 Import",
{})
ADD_CUSTOM_MUTATORS({&ASN1MutatorFlipConstructed, &ASN1MutatorChangeType})

View File

@ -0,0 +1,83 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "FuzzerInternal.h"
#include "asn1_mutators.h"
#include "shared.h"
const std::vector<const SEC_ASN1Template *> templates = {
CERT_AttributeTemplate,
CERT_CertExtensionTemplate,
CERT_CertificateRequestTemplate,
CERT_CertificateTemplate,
CERT_CrlTemplate,
CERT_IssuerAndSNTemplate,
CERT_NameTemplate,
CERT_PublicKeyAndChallengeTemplate,
CERT_RDNTemplate,
CERT_SequenceOfCertExtensionTemplate,
CERT_SetOfAttributeTemplate,
CERT_SetOfSignedCrlTemplate,
CERT_SignedCrlTemplate,
CERT_SignedDataTemplate,
CERT_SubjectPublicKeyInfoTemplate,
CERT_TimeChoiceTemplate,
CERT_ValidityTemplate,
SEC_AnyTemplate,
SEC_BitStringTemplate,
SEC_BMPStringTemplate,
SEC_BooleanTemplate,
SEC_CertSequenceTemplate,
SEC_EnumeratedTemplate,
SEC_GeneralizedTimeTemplate,
SEC_IA5StringTemplate,
SEC_IntegerTemplate,
SEC_NullTemplate,
SEC_ObjectIDTemplate,
SEC_OctetStringTemplate,
SEC_PointerToAnyTemplate,
SEC_PointerToEnumeratedTemplate,
SEC_PointerToGeneralizedTimeTemplate,
SEC_PointerToOctetStringTemplate,
SEC_PrintableStringTemplate,
SEC_SetOfAnyTemplate,
SEC_SetOfEnumeratedTemplate,
SEC_SequenceOfAnyTemplate,
SEC_SequenceOfObjectIDTemplate,
SEC_SignedCertificateTemplate,
SEC_SkipTemplate,
SEC_T61StringTemplate,
SEC_UniversalStringTemplate,
SEC_UTCTimeTemplate,
SEC_UTF8StringTemplate,
SEC_VisibleStringTemplate,
SECKEY_DHParamKeyTemplate,
SECKEY_DHPublicKeyTemplate,
SECKEY_DSAPrivateKeyExportTemplate,
SECKEY_DSAPublicKeyTemplate,
SECKEY_PQGParamsTemplate,
SECKEY_PrivateKeyInfoTemplate,
SECKEY_RSAPSSParamsTemplate,
SECKEY_RSAPublicKeyTemplate,
SECOID_AlgorithmIDTemplate};
extern const uint16_t DEFAULT_MAX_LENGTH = 10000U;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
char *dest[2048];
for (auto tpl : templates) {
PORTCheapArenaPool pool;
SECItem buf = {siBuffer, const_cast<unsigned char *>(Data),
static_cast<unsigned int>(Size)};
PORT_InitCheapArena(&pool, DER_DEFAULT_CHUNKSIZE);
(void)SEC_QuickDERDecodeItem(&pool.arena, dest, tpl, &buf);
PORT_DestroyCheapArena(&pool);
}
return 0;
}
ADD_CUSTOM_MUTATORS({&ASN1MutatorFlipConstructed, &ASN1MutatorChangeType})

View File

@ -1,38 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <stdint.h>
#include "asn1_mutators.h"
#include "cert.h"
#include "registry.h"
void QuickDERDecode(void *dst, const SEC_ASN1Template *tpl, const uint8_t *buf,
size_t len) {
PORTCheapArenaPool pool;
SECItem data = {siBuffer, const_cast<unsigned char *>(buf),
static_cast<unsigned int>(len)};
PORT_InitCheapArena(&pool, DER_DEFAULT_CHUNKSIZE);
(void)SEC_QuickDERDecodeItem(&pool.arena, dst, tpl, &data);
PORT_DestroyCheapArena(&pool);
}
extern "C" int cert_fuzzing_target(const uint8_t *Data, size_t Size) {
CERTCertificate cert;
QuickDERDecode(&cert, SEC_SignedCertificateTemplate, Data, Size);
return 0;
}
REGISTER_FUZZING_TARGET("cert", cert_fuzzing_target, 3072, "Certificate Import",
{&ASN1MutatorFlipConstructed, &ASN1MutatorChangeType})
extern "C" int spki_fuzzing_target(const uint8_t *Data, size_t Size) {
CERTSubjectPublicKeyInfo spki;
QuickDERDecode(&spki, CERT_SubjectPublicKeyInfoTemplate, Data, Size);
return 0;
}
REGISTER_FUZZING_TARGET("spki", spki_fuzzing_target, 1024, "SPKI Import",
{&ASN1MutatorFlipConstructed, &ASN1MutatorChangeType})

View File

@ -1,79 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef registry_h__
#define registry_h__
#include <map>
#include "FuzzerInternal.h"
#include "nss.h"
using namespace fuzzer;
using namespace std;
typedef decltype(LLVMFuzzerCustomMutator)* Mutator;
class Registry {
public:
static void Add(string name, UserCallback func, uint16_t max_len, string desc,
vector<Mutator> mutators = {}) {
assert(!Has(name));
GetInstance().targets_[name] = TargetData(func, max_len, desc, mutators);
}
static bool Has(string name) {
return GetInstance().targets_.count(name) > 0;
}
static UserCallback Func(string name) {
assert(Has(name));
return get<0>(Get(name));
}
static uint16_t MaxLen(string name) {
assert(Has(name));
return get<1>(Get(name));
}
static string& Desc(string name) {
assert(Has(name));
return get<2>(Get(name));
}
static vector<Mutator>& Mutators(string name) {
assert(Has(name));
return get<3>(Get(name));
}
static vector<string> Names() {
vector<string> names;
for (auto& it : GetInstance().targets_) {
names.push_back(it.first);
}
return names;
}
private:
typedef tuple<UserCallback, uint16_t, string, vector<Mutator>> TargetData;
static Registry& GetInstance() {
static Registry registry;
return registry;
}
static TargetData& Get(string name) { return GetInstance().targets_[name]; }
Registry() {}
map<string, TargetData> targets_;
};
#define REGISTER_FUZZING_TARGET(name, func, max_len, desc, ...) \
static void __attribute__((constructor)) Register_##func() { \
Registry::Add(name, func, max_len, desc, __VA_ARGS__); \
}
#endif // registry_h__

View File

@ -7,6 +7,8 @@
#ifndef shared_h__
#define shared_h__
#include "FuzzerRandom.h"
#include "cert.h"
#include "nss.h"
class NSSDatabase {
@ -15,4 +17,23 @@ class NSSDatabase {
~NSSDatabase() { NSS_Shutdown(); }
};
size_t CustomMutate(std::vector<decltype(LLVMFuzzerCustomMutator) *> mutators,
uint8_t *Data, size_t Size, size_t MaxSize,
unsigned int Seed) {
fuzzer::Random R(Seed);
if (R.RandBool()) {
auto idx = R(mutators.size());
return mutators.at(idx)(Data, Size, MaxSize, Seed);
}
return LLVMFuzzerMutate(Data, Size, MaxSize);
}
#define ADD_CUSTOM_MUTATORS(...) \
extern "C" size_t LLVMFuzzerCustomMutator( \
uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed) { \
return CustomMutate(__VA_ARGS__, Data, Size, MaxSize, Seed); \
}
#endif // shared_h__

View File

@ -0,0 +1,17 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "FuzzerInternal.h"
#include "asn1_mutators.h"
#include "shared.h"
extern const uint16_t DEFAULT_MAX_LENGTH = 1024U;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
CERTSubjectPublicKeyInfo spki;
QuickDERDecode(&spki, CERT_SubjectPublicKeyInfoTemplate, Data, Size);
return 0;
}
ADD_CUSTOM_MUTATORS({&ASN1MutatorFlipConstructed, &ASN1MutatorChangeType})

View File

@ -1,15 +1,16 @@
##############################################
## ##
## WARNING: You're building with -Dfuzz=1 ##
## ##
## This means: ##
## ##
## * Your PRNG is DETERMINISTIC. ##
## * TLS transcripts are PLAINTEXT. ##
## * TLS signature checks are DISABLED. ##
## ##
## Thank you for fuzzing! ##
## ##
##############################################
##################################################
## ##
## WARNING: You're building with -Dfuzz_tls=1 ##
## ##
## This means: ##
## ##
## * Your PRNG is DETERMINISTIC. ##
## * TLS transcripts are PLAINTEXT. ##
## * Session tickets are NOT encrypted. ##
## * TLS signature/MAC checks are DISABLED. ##
## ##
## Thank you for fuzzing! ##
## ##
##################################################

View File

@ -1,35 +0,0 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
{
'includes': [
'../../coreconf/config.gypi',
'gtest.gypi',
],
'targets': [
{
'target_name': 'gtests',
'type': 'executable',
'sources': [
'gtests.cc'
],
'dependencies': [
'<(DEPTH)/exports.gyp:nss_exports',
'<(DEPTH)/lib/nss/nss.gyp:nss3',
'<(DEPTH)/lib/util/util.gyp:nssutil3',
'<(DEPTH)/lib/smime/smime.gyp:smime3',
'<(DEPTH)/gtests/google_test/google_test.gyp:gtest',
'<(DEPTH)/cmd/lib/lib.gyp:sectool'
]
}
],
'target_defaults': {
'include_dirs': [
'../../gtests/google_test/gtest/include',
'../../gtests/common'
],
},
'variables': {
'module': 'nss'
}
}

View File

@ -2,9 +2,6 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
{
'includes': [
'../../coreconf/config.gypi'
],
'target_defaults': {
'conditions': [
['OS=="win"', {
@ -17,7 +14,7 @@
'-lstdc++',
],
}],
[ 'fuzz==1', {
[ 'fuzz_tls==1', {
'defines': [
'UNSAFE_FUZZER_MODE',
],

View File

@ -19,8 +19,12 @@
'<(DEPTH)/lib/freebl/freebl.gyp:<(freebl_name)',
'<(DEPTH)/gtests/google_test/google_test.gyp:gtest',
],
'defines': [
'CT_VERIF',
'conditions': [
[ 'ct_verif==1', {
'defines': [
'CT_VERIF',
],
}],
],
}
],

View File

@ -83,8 +83,10 @@ TEST_F(MPITest, MpiCmpConstTest) {
"FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632550"),
16);
#ifdef CT_VERIF
mp_taint(&b);
mp_taint(&c);
#endif
uint32_t runs = 5000000;
uint32_t time_b = 0, time_c = 0;

View File

@ -12,20 +12,16 @@
#include "nss.h"
#include "prio.h"
#include "prnetdb.h"
#include "secerr.h"
#include "ssl.h"
#include "ssl3prot.h"
#include "sslerr.h"
#include "sslproto.h"
#include "ssl3prot.h"
#include "nsskeys.h"
static const char* kVersionDisableFlags[] = {
"no-ssl3",
"no-tls1",
"no-tls11",
"no-tls12",
"no-tls13"
};
static const char* kVersionDisableFlags[] = {"no-ssl3", "no-tls1", "no-tls11",
"no-tls12", "no-tls13"};
bool exitCodeUnimplemented = false;
@ -154,8 +150,7 @@ class TestAgent {
}
static bool ConvertFromWireVersion(SSLProtocolVariant variant,
int wire_version,
uint16_t* lib_version) {
int wire_version, uint16_t* lib_version) {
// These default values are used when {min,max}-version isn't given.
if (wire_version == 0 || wire_version == 0xffff) {
*lib_version = static_cast<uint16_t>(wire_version);
@ -171,18 +166,18 @@ class TestAgent {
if (variant == ssl_variant_datagram) {
switch (wire_version) {
case SSL_LIBRARY_VERSION_DTLS_1_0_WIRE:
*lib_version = SSL_LIBRARY_VERSION_DTLS_1_0;
break;
case SSL_LIBRARY_VERSION_DTLS_1_2_WIRE:
*lib_version = SSL_LIBRARY_VERSION_DTLS_1_2;
break;
case SSL_LIBRARY_VERSION_DTLS_1_3_WIRE:
*lib_version = SSL_LIBRARY_VERSION_DTLS_1_3;
break;
default:
std::cerr << "Unrecognized DTLS version " << wire_version << ".\n";
return false;
case SSL_LIBRARY_VERSION_DTLS_1_0_WIRE:
*lib_version = SSL_LIBRARY_VERSION_DTLS_1_0;
break;
case SSL_LIBRARY_VERSION_DTLS_1_2_WIRE:
*lib_version = SSL_LIBRARY_VERSION_DTLS_1_2;
break;
case SSL_LIBRARY_VERSION_DTLS_1_3_WIRE:
*lib_version = SSL_LIBRARY_VERSION_DTLS_1_3;
break;
default:
std::cerr << "Unrecognized DTLS version " << wire_version << ".\n";
return false;
}
} else {
if (wire_version < SSL_LIBRARY_VERSION_3_0 ||
@ -220,7 +215,7 @@ class TestAgent {
// Ignore -no-ssl3, because SSLv3 is never supported.
for (size_t i = 1; i < PR_ARRAY_SIZE(kVersionDisableFlags); ++i) {
auto version =
static_cast<uint16_t>(SSL_LIBRARY_VERSION_TLS_1_0 + (i - 1));
static_cast<uint16_t>(SSL_LIBRARY_VERSION_TLS_1_0 + (i - 1));
if (variant == ssl_variant_datagram) {
// In DTLS mode, the -no-tlsN flags refer to DTLS versions,
// but NSS wants the corresponding TLS versions.
@ -348,12 +343,53 @@ class TestAgent {
rv = PR_Write(ssl_fd_, block, len);
if (rv != len) {
std::cerr << "Write failure\n";
PORT_SetError(SEC_ERROR_OUTPUT_LEN);
return SECFailure;
}
}
return SECSuccess;
}
// Write bytes to the other side then read them back and check
// that they were correctly XORed as in ReadWrite.
SECStatus WriteRead() {
static const uint8_t ch = 'E';
// We do 600-byte blocks to provide mis-alignment of the
// reader and writer.
uint8_t block[600];
memset(block, ch, sizeof(block));
int32_t rv = PR_Write(ssl_fd_, block, sizeof(block));
if (rv != sizeof(block)) {
std::cerr << "Write failure\n";
PORT_SetError(SEC_ERROR_OUTPUT_LEN);
return SECFailure;
}
size_t left = sizeof(block);
while (left) {
int32_t rv = PR_Read(ssl_fd_, block, left);
if (rv < 0) {
std::cerr << "Failure reading\n";
return SECFailure;
}
if (rv == 0) {
PORT_SetError(SEC_ERROR_INPUT_LEN);
return SECFailure;
}
int32_t len = rv;
for (int32_t i = 0; i < len; ++i) {
if (block[i] != (ch ^ 0xff)) {
PORT_SetError(SEC_ERROR_BAD_DATA);
return SECFailure;
}
}
left -= len;
}
return SECSuccess;
}
SECStatus DoExchange() {
SECStatus rv = Handshake();
if (rv != SECSuccess) {
@ -363,12 +399,22 @@ class TestAgent {
return SECFailure;
}
rv = ReadWrite();
if (rv != SECSuccess) {
PRErrorCode err = PR_GetError();
std::cerr << "ReadWrite failed with error=" << FormatError(err)
<< std::endl;
return SECFailure;
if (cfg_.get<bool>("write-then-read")) {
rv = WriteRead();
if (rv != SECSuccess) {
PRErrorCode err = PR_GetError();
std::cerr << "WriteRead failed with error=" << FormatError(err)
<< std::endl;
return SECFailure;
}
} else {
rv = ReadWrite();
if (rv != SECSuccess) {
PRErrorCode err = PR_GetError();
std::cerr << "ReadWrite failed with error=" << FormatError(err)
<< std::endl;
return SECFailure;
}
}
return SECSuccess;
@ -395,6 +441,7 @@ std::unique_ptr<const Config> ReadConfig(int argc, char** argv) {
for (auto flag : kVersionDisableFlags) {
cfg->AddEntry<bool>(flag, false);
}
cfg->AddEntry<bool>("write-then-read", false);
auto rv = cfg->ParseArgs(argc, argv);
switch (rv) {
@ -410,7 +457,6 @@ std::unique_ptr<const Config> ReadConfig(int argc, char** argv) {
return std::move(cfg);
}
bool RunCycle(std::unique_ptr<const Config>& cfg) {
std::unique_ptr<TestAgent> agent(TestAgent::Create(*cfg));
return agent && agent->DoExchange() == SECSuccess;

View File

@ -35,9 +35,6 @@
'<(DEPTH)/lib/dev/dev.gyp:nssdev',
'<(DEPTH)/lib/base/base.gyp:nssb',
'<(DEPTH)/lib/freebl/freebl.gyp:freebl',
'<(DEPTH)/lib/nss/nss.gyp:nss_static',
'<(DEPTH)/lib/pk11wrap/pk11wrap.gyp:pk11wrap',
'<(DEPTH)/lib/certhigh/certhigh.gyp:certhi',
'<(DEPTH)/lib/zlib/zlib.gyp:nss_zlib'
],
'conditions': [

View File

@ -26,6 +26,7 @@ CPPSRCS = \
ssl_extension_unittest.cc \
ssl_fragment_unittest.cc \
ssl_fuzz_unittest.cc \
ssl_gather_unittest.cc \
ssl_gtest.cc \
ssl_hrr_unittest.cc \
ssl_loopback_unittest.cc \

View File

@ -227,7 +227,7 @@ TEST_P(TlsConnectTls13, TestTls13ZeroRttDowngrade) {
client_->Handshake();
server_->Handshake();
ASSERT_TRUE_WAIT(
(client_->error_code() == SSL_ERROR_RX_MALFORMED_SERVER_HELLO), 2000);
(client_->error_code() == SSL_ERROR_DOWNGRADE_WITH_EARLY_DATA), 2000);
// DTLS will timeout as we bump the epoch when installing the early app data
// cipher suite. Thus the encrypted alert will be ignored.
@ -266,7 +266,7 @@ TEST_P(TlsConnectTls13, TestTls13ZeroRttDowngradeEarlyData) {
client_->Handshake();
server_->Handshake();
ASSERT_TRUE_WAIT(
(client_->error_code() == SSL_ERROR_RX_MALFORMED_SERVER_HELLO), 2000);
(client_->error_code() == SSL_ERROR_DOWNGRADE_WITH_EARLY_DATA), 2000);
// DTLS will timeout as we bump the epoch when installing the early app data
// cipher suite. Thus the encrypted alert will be ignored.

View File

@ -191,6 +191,58 @@ TEST_P(TlsConnectGenericPre13, P384PriorityFromModelSocket) {
ssl_sig_rsa_pss_sha256);
}
class TlsKeyExchangeGroupCapture : public TlsHandshakeFilter {
public:
TlsKeyExchangeGroupCapture() : group_(ssl_grp_none) {}
SSLNamedGroup group() const { return group_; }
protected:
virtual PacketFilter::Action FilterHandshake(const HandshakeHeader &header,
const DataBuffer &input,
DataBuffer *output) {
if (header.handshake_type() != kTlsHandshakeServerKeyExchange) {
return KEEP;
}
uint32_t value = 0;
EXPECT_TRUE(input.Read(0, 1, &value));
EXPECT_EQ(3U, value) << "curve type has to be 3";
EXPECT_TRUE(input.Read(1, 2, &value));
group_ = static_cast<SSLNamedGroup>(value);
return KEEP;
}
private:
SSLNamedGroup group_;
};
// If we strip the client's supported groups extension, the server should assume
// P-256 is supported by the client (<= 1.2 only).
TEST_P(TlsConnectGenericPre13, DropSupportedGroupExtensionP256) {
EnsureTlsSetup();
client_->SetPacketFilter(new TlsExtensionDropper(ssl_supported_groups_xtn));
auto group_capture = new TlsKeyExchangeGroupCapture();
server_->SetPacketFilter(group_capture);
ConnectExpectFail();
client_->CheckErrorCode(SSL_ERROR_DECRYPT_ERROR_ALERT);
server_->CheckErrorCode(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
EXPECT_EQ(ssl_grp_ec_secp256r1, group_capture->group());
}
// Supported groups is mandatory in TLS 1.3.
TEST_P(TlsConnectTls13, DropSupportedGroupExtension) {
EnsureTlsSetup();
client_->SetPacketFilter(new TlsExtensionDropper(ssl_supported_groups_xtn));
ConnectExpectFail();
client_->CheckErrorCode(SSL_ERROR_MISSING_EXTENSION_ALERT);
server_->CheckErrorCode(SSL_ERROR_MISSING_SUPPORTED_GROUPS_EXTENSION);
}
// If we only have a lame group, we fall back to static RSA.
TEST_P(TlsConnectGenericPre13, UseLameGroup) {
const std::vector<SSLNamedGroup> groups = {ssl_grp_ec_secp192r1};

View File

@ -0,0 +1,153 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "gtest_utils.h"
#include "tls_connect.h"
namespace nss_test {
class GatherV2ClientHelloTest : public TlsConnectTestBase {
public:
GatherV2ClientHelloTest() : TlsConnectTestBase(STREAM, 0) {}
void ConnectExpectMalformedClientHello(const DataBuffer &data) {
EnsureTlsSetup();
auto alert_recorder = new TlsAlertRecorder();
server_->SetPacketFilter(alert_recorder);
client_->SendDirect(data);
server_->StartConnect();
server_->Handshake();
ASSERT_TRUE_WAIT(
(server_->error_code() == SSL_ERROR_RX_MALFORMED_CLIENT_HELLO), 2000);
EXPECT_EQ(kTlsAlertFatal, alert_recorder->level());
EXPECT_EQ(illegal_parameter, alert_recorder->description());
}
};
// Gather a 5-byte v3 record, with a zero fragment length. The empty handshake
// message should be ignored, and the connection will succeed afterwards.
TEST_F(TlsConnectTest, GatherEmptyV3Record) {
DataBuffer buffer;
size_t idx = 0;
idx = buffer.Write(idx, 0x16, 1); // handshake
idx = buffer.Write(idx, 0x0301, 2); // record_version
(void)buffer.Write(idx, 0U, 2); // length=0
EnsureTlsSetup();
client_->SendDirect(buffer);
Connect();
}
// Gather a 5-byte v3 record, with a fragment length exceeding the maximum.
TEST_F(TlsConnectTest, GatherExcessiveV3Record) {
DataBuffer buffer;
size_t idx = 0;
idx = buffer.Write(idx, 0x16, 1); // handshake
idx = buffer.Write(idx, 0x0301, 2); // record_version
(void)buffer.Write(idx, MAX_FRAGMENT_LENGTH + 2048 + 1, 2); // length=max+1
EnsureTlsSetup();
auto alert_recorder = new TlsAlertRecorder();
server_->SetPacketFilter(alert_recorder);
client_->SendDirect(buffer);
server_->StartConnect();
server_->Handshake();
ASSERT_TRUE_WAIT((server_->error_code() == SSL_ERROR_RX_RECORD_TOO_LONG),
2000);
EXPECT_EQ(kTlsAlertFatal, alert_recorder->level());
EXPECT_EQ(record_overflow, alert_recorder->description());
}
// Gather a 3-byte v2 header, with a fragment length of 2.
TEST_F(GatherV2ClientHelloTest, GatherV2RecordLongHeader) {
DataBuffer buffer;
size_t idx = 0;
idx = buffer.Write(idx, 0x0002, 2); // length=2 (long header)
idx = buffer.Write(idx, 0U, 1); // padding=0
(void)buffer.Write(idx, 0U, 2); // data
ConnectExpectMalformedClientHello(buffer);
}
// Gather a 3-byte v2 header, with a fragment length of 1.
TEST_F(GatherV2ClientHelloTest, GatherV2RecordLongHeader2) {
DataBuffer buffer;
size_t idx = 0;
idx = buffer.Write(idx, 0x0001, 2); // length=1 (long header)
idx = buffer.Write(idx, 0U, 1); // padding=0
idx = buffer.Write(idx, 0U, 1); // data
(void)buffer.Write(idx, 0U, 1); // surplus (need 5 bytes total)
ConnectExpectMalformedClientHello(buffer);
}
// Gather a 3-byte v2 header, with a zero fragment length.
TEST_F(GatherV2ClientHelloTest, GatherEmptyV2RecordLongHeader) {
DataBuffer buffer;
size_t idx = 0;
idx = buffer.Write(idx, 0U, 2); // length=0 (long header)
idx = buffer.Write(idx, 0U, 1); // padding=0
(void)buffer.Write(idx, 0U, 2); // surplus (need 5 bytes total)
ConnectExpectMalformedClientHello(buffer);
}
// Gather a 2-byte v2 header, with a fragment length of 3.
TEST_F(GatherV2ClientHelloTest, GatherV2RecordShortHeader) {
DataBuffer buffer;
size_t idx = 0;
idx = buffer.Write(idx, 0x8003, 2); // length=3 (short header)
(void)buffer.Write(idx, 0U, 3); // data
ConnectExpectMalformedClientHello(buffer);
}
// Gather a 2-byte v2 header, with a fragment length of 2.
TEST_F(GatherV2ClientHelloTest, GatherEmptyV2RecordShortHeader2) {
DataBuffer buffer;
size_t idx = 0;
idx = buffer.Write(idx, 0x8002, 2); // length=2 (short header)
idx = buffer.Write(idx, 0U, 2); // data
(void)buffer.Write(idx, 0U, 1); // surplus (need 5 bytes total)
ConnectExpectMalformedClientHello(buffer);
}
// Gather a 2-byte v2 header, with a fragment length of 1.
TEST_F(GatherV2ClientHelloTest, GatherEmptyV2RecordShortHeader3) {
DataBuffer buffer;
size_t idx = 0;
idx = buffer.Write(idx, 0x8001, 2); // length=1 (short header)
idx = buffer.Write(idx, 0U, 1); // data
(void)buffer.Write(idx, 0U, 2); // surplus (need 5 bytes total)
ConnectExpectMalformedClientHello(buffer);
}
// Gather a 2-byte v2 header, with a zero fragment length.
TEST_F(GatherV2ClientHelloTest, GatherEmptyV2RecordShortHeader) {
DataBuffer buffer;
size_t idx = 0;
idx = buffer.Write(idx, 0x8000, 2); // length=0 (short header)
(void)buffer.Write(idx, 0U, 3); // surplus (need 5 bytes total)
ConnectExpectMalformedClientHello(buffer);
}
} // namespace nss_test

View File

@ -26,6 +26,7 @@
'ssl_extension_unittest.cc',
'ssl_fuzz_unittest.cc',
'ssl_fragment_unittest.cc',
'ssl_gather_unittest.cc',
'ssl_gtest.cc',
'ssl_hrr_unittest.cc',
'ssl_loopback_unittest.cc',

View File

@ -202,6 +202,28 @@ TEST_P(SSLv2ClientHelloTest, Connect) {
Connect();
}
// Sending a v2 ClientHello after a no-op v3 record must fail.
TEST_P(SSLv2ClientHelloTest, ConnectAfterEmptyV3Record) {
DataBuffer buffer;
size_t idx = 0;
idx = buffer.Write(idx, 0x16, 1); // handshake
idx = buffer.Write(idx, 0x0301, 2); // record_version
(void)buffer.Write(idx, 0U, 2); // length=0
SetAvailableCipherSuite(TLS_DHE_RSA_WITH_AES_128_CBC_SHA);
EnsureTlsSetup();
client_->SendDirect(buffer);
// Need padding so the connection doesn't just time out. With a v2
// ClientHello parsed as a v3 record we will use the record version
// as the record length.
SetPadding(255);
ConnectExpectFail();
EXPECT_EQ(SSL_ERROR_BAD_CLIENT, server_->error_code());
}
// Test negotiating TLS 1.3.
TEST_F(SSLv2ClientHelloTestF, Connect13) {
EnsureTlsSetup();

File diff suppressed because it is too large Load Diff

View File

@ -45,8 +45,8 @@
* of the comment in the CK_VERSION type definition.
*/
#define NSS_BUILTINS_LIBRARY_VERSION_MAJOR 2
#define NSS_BUILTINS_LIBRARY_VERSION_MINOR 10
#define NSS_BUILTINS_LIBRARY_VERSION "2.10"
#define NSS_BUILTINS_LIBRARY_VERSION_MINOR 11
#define NSS_BUILTINS_LIBRARY_VERSION "2.11"
/* These version numbers detail the semantic changes to the ckfw engine. */
#define NSS_BUILTINS_HARDWARE_VERSION_MAJOR 1

View File

@ -166,12 +166,16 @@ static SECItem *
common_DecodeDerSig(const SECItem *item, unsigned int len)
{
SECItem *result = NULL;
PORTCheapArenaPool arena;
SECStatus status;
DSA_ASN1Signature sig;
SECItem dst;
PORT_Memset(&sig, 0, sizeof(sig));
/* Make enough room for r + s. */
PORT_InitCheapArena(&arena, PR_MAX(2 * MAX_ECKEY_LEN, DSA_MAX_SIGNATURE_LEN));
result = PORT_ZNew(SECItem);
if (result == NULL)
goto loser;
@ -183,7 +187,7 @@ common_DecodeDerSig(const SECItem *item, unsigned int len)
sig.r.type = siUnsignedInteger;
sig.s.type = siUnsignedInteger;
status = SEC_ASN1DecodeItem(NULL, &sig, DSA_SignatureTemplate, item);
status = SEC_QuickDERDecodeItem(&arena.arena, &sig, DSA_SignatureTemplate, item);
if (status != SECSuccess)
goto loser;
@ -202,10 +206,7 @@ common_DecodeDerSig(const SECItem *item, unsigned int len)
goto loser;
done:
if (sig.r.data != NULL)
PORT_Free(sig.r.data);
if (sig.s.data != NULL)
PORT_Free(sig.s.data);
PORT_DestroyCheapArena(&arena);
return result;

View File

@ -91,7 +91,7 @@ nssSlot_ResetDelay(
}
static PRBool
within_token_delay_period(NSSSlot *slot)
within_token_delay_period(const NSSSlot *slot)
{
PRIntervalTime time, lastTime;
/* Set the delay time for checking the token presence */
@ -103,7 +103,6 @@ within_token_delay_period(NSSSlot *slot)
if ((lastTime) && ((time - lastTime) < s_token_delay_time)) {
return PR_TRUE;
}
slot->lastTokenPing = time;
return PR_FALSE;
}
@ -136,6 +135,7 @@ nssSlot_IsTokenPresent(
nssSlot_ExitMonitor(slot);
if (ckrv != CKR_OK) {
slot->token->base.name[0] = 0; /* XXX */
slot->lastTokenPing = PR_IntervalNow();
return PR_FALSE;
}
slot->ckFlags = slotInfo.flags;
@ -143,6 +143,7 @@ nssSlot_IsTokenPresent(
if ((slot->ckFlags & CKF_TOKEN_PRESENT) == 0) {
if (!slot->token) {
/* token was never present */
slot->lastTokenPing = PR_IntervalNow();
return PR_FALSE;
}
session = nssToken_GetDefaultSession(slot->token);
@ -165,6 +166,7 @@ nssSlot_IsTokenPresent(
slot->token->base.name[0] = 0; /* XXX */
/* clear the token cache */
nssToken_Remove(slot->token);
slot->lastTokenPing = PR_IntervalNow();
return PR_FALSE;
}
/* token is present, use the session info to determine if the card
@ -187,8 +189,10 @@ nssSlot_IsTokenPresent(
isPresent = session->handle != CK_INVALID_SESSION;
nssSession_ExitMonitor(session);
/* token not removed, finished */
if (isPresent)
if (isPresent) {
slot->lastTokenPing = PR_IntervalNow();
return PR_TRUE;
}
}
/* the token has been removed, and reinserted, or the slot contains
* a token it doesn't recognize. invalidate all the old
@ -201,8 +205,11 @@ nssSlot_IsTokenPresent(
if (nssrv != PR_SUCCESS) {
slot->token->base.name[0] = 0; /* XXX */
slot->ckFlags &= ~CKF_TOKEN_PRESENT;
/* TODO: insert a barrier here to avoid reordering of the assingments */
slot->lastTokenPing = PR_IntervalNow();
return PR_FALSE;
}
slot->lastTokenPing = PR_IntervalNow();
return PR_TRUE;
}

View File

@ -601,7 +601,7 @@ $(ECL_OBJS): $(ECL_HDRS)
$(OBJDIR)/sysrand$(OBJ_SUFFIX): sysrand.c unix_rand.c win_rand.c os2_rand.c
$(OBJDIR)/sysrand$(OBJ_SUFFIX): sysrand.c unix_rand.c win_rand.c
$(OBJDIR)/$(PROG_PREFIX)mpprime$(OBJ_SUFFIX): primes.c

View File

@ -566,6 +566,15 @@ ECDH_Derive(SECItem *publicValue,
return SECFailure;
}
/*
* Make sure the point is on the requested curve to avoid
* certain small subgroup attacks.
*/
if (EC_ValidatePublicKey(ecParams, publicValue) != SECSuccess) {
PORT_SetError(SEC_ERROR_BAD_KEY);
return SECFailure;
}
/* Perform curve specific multiplication using ECMethod */
if (ecParams->fieldID.type == ec_field_plain) {
const ECMethod *method;
@ -581,10 +590,6 @@ ECDH_Derive(SECItem *publicValue,
PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
return SECFailure;
}
if (method->validate(publicValue) != SECSuccess) {
PORT_SetError(SEC_ERROR_BAD_KEY);
return SECFailure;
}
return method->mul(derivedSecret, privateValue, publicValue);
}
@ -1002,9 +1007,14 @@ ECDSA_VerifyDigest(ECPublicKey *key, const SECItem *signature,
}
slen = signature->len / 2;
/*
* The incoming point has been verified in sftk_handlePublicKeyObject.
*/
SECITEM_AllocItem(NULL, &pointC, ecParams->pointSize);
if (pointC.data == NULL)
if (pointC.data == NULL) {
goto cleanup;
}
CHECK_MPI_OK(mp_init(&r_));
CHECK_MPI_OK(mp_init(&s_));

View File

@ -90,20 +90,6 @@ the linear coefficient in the curve defining equation).
ecp_192.c and ecp_224.c provide optimized field arithmetic.
Point Arithmetic over Binary Polynomial Fields
----------------------------------------------
ec2_aff.c provides point arithmetic using affine coordinates.
ec2_proj.c provides point arithmetic using projective coordinates.
(Projective coordinates represent a point (x, y) as (X, Y, Z), where
x=X/Z, y=Y/Z^2).
ec2_mont.c provides point multiplication using Montgomery projective
coordinates.
ec2_163.c, ec2_193.c, and ec2_233.c provide optimized field arithmetic.
Field Arithmetic
----------------
@ -126,18 +112,6 @@ fields defined by nistp192 and nistp224 primes.
ecl_gf.c provides wrappers around the basic field operations.
Binary Polynomial Field Arithmetic
----------------------------------
../mpi/mp_gf2m.c provides basic binary polynomial field arithmetic,
including addition, multiplication, squaring, mod, and division, as well
as conversion ob polynomial representations between bitstring and int[].
ec2_163.c, ec2_193.c, and ec2_233.c provide optimized field mod, mul,
and sqr operations.
ecl_gf.c provides wrappers around the basic field operations.
Field Encoding
--------------
@ -187,81 +161,3 @@ arithmetic. Instead, they use basic field arithmetic with their
optimized reduction (as in ecp_192.c and ecp_224.c). They
use the same point multiplication and simultaneous point multiplication
algorithms as other curves over prime fields.
Curves over binary polynomial fields by default use generic field
arithmetic with montgomery point multiplication and basic kP + lQ
computation (multiply, multiply, and add). (Wiring in function
ECGroup_cons_GF2m in ecl.c.)
Curves over binary polynomial fields that have optimized field
arithmetic (i.e., any 163-, 193, or 233-bit field) use their optimized
field arithmetic. They use the same point multiplication and
simultaneous point multiplication algorithms as other curves over binary
fields.
Example
-------
We provide an example for plugging in an optimized implementation for
the Koblitz curve nistk163.
Suppose the file ec2_k163.c contains the optimized implementation. In
particular it contains a point multiplication function:
mp_err ec_GF2m_nistk163_pt_mul(const mp_int *n, const mp_int *px,
const mp_int *py, mp_int *rx, mp_int *ry, const ECGroup *group);
Since only a pt_mul function is provided, the generic pt_add function
will be used.
There are two options for handling the optimized field arithmetic used
by the ..._pt_mul function. Say the optimized field arithmetic includes
the following functions:
mp_err ec_GF2m_nistk163_add(const mp_int *a, const mp_int *b,
mp_int *r, const GFMethod *meth);
mp_err ec_GF2m_nistk163_mul(const mp_int *a, const mp_int *b,
mp_int *r, const GFMethod *meth);
mp_err ec_GF2m_nistk163_sqr(const mp_int *a, const mp_int *b,
mp_int *r, const GFMethod *meth);
mp_err ec_GF2m_nistk163_div(const mp_int *a, const mp_int *b,
mp_int *r, const GFMethod *meth);
First, the optimized field arithmetic could simply be called directly
by the ..._pt_mul function. This would be accomplished by changing
the ecgroup_fromNameAndHex function in ecl.c to include the following
statements:
if (name == ECCurve_NIST_K163) {
group = ECGroup_consGF2m(&irr, NULL, &curvea, &curveb, &genx,
&geny, &order, params->cofactor);
if (group == NULL) { res = MP_UNDEF; goto CLEANUP; }
MP_CHECKOK( ec_group_set_nistk163(group) );
}
and including in ec2_k163.c the following function:
mp_err ec_group_set_nistk163(ECGroup *group) {
group->point_mul = &ec_GF2m_nistk163_pt_mul;
return MP_OKAY;
}
As a result, ec_GF2m_pt_add and similar functions would use the
basic binary polynomial field arithmetic ec_GF2m_add, ec_GF2m_mul,
ec_GF2m_sqr, and ec_GF2m_div.
Alternatively, the optimized field arithmetic could be wired into the
group's GFMethod. This would be accomplished by putting the following
function in ec2_k163.c:
mp_err ec_group_set_nistk163(ECGroup *group) {
group->meth->field_add = &ec_GF2m_nistk163_add;
group->meth->field_mul = &ec_GF2m_nistk163_mul;
group->meth->field_sqr = &ec_GF2m_nistk163_sqr;
group->meth->field_div = &ec_GF2m_nistk163_div;
group->point_mul = &ec_GF2m_nistk163_pt_mul;
return MP_OKAY;
}
For an example of functions that use special field encodings, take a
look at ecp_mont.c.

View File

@ -1,121 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mpi.h"
#include "mplogic.h"
#include "ecl.h"
#include "ecp.h"
#include "ecl-priv.h"
#include <sys/types.h>
#include <stdio.h>
#include <time.h>
#include <sys/time.h>
#include <sys/resource.h>
/* Returns 2^e as an integer. This is meant to be used for small powers of
* two. */
int ec_twoTo(int e);
/* Number of bits of scalar to test */
#define BITSIZE 160
/* Time k repetitions of operation op. */
#define M_TimeOperation(op, k) \
{ \
double dStart, dNow, dUserTime; \
struct rusage ru; \
int i; \
getrusage(RUSAGE_SELF, &ru); \
dStart = (double)ru.ru_utime.tv_sec + (double)ru.ru_utime.tv_usec * 0.000001; \
for (i = 0; i < k; i++) { \
{ \
op; \
} \
}; \
getrusage(RUSAGE_SELF, &ru); \
dNow = (double)ru.ru_utime.tv_sec + (double)ru.ru_utime.tv_usec * 0.000001; \
dUserTime = dNow - dStart; \
if (dUserTime) \
printf(" %-45s\n k: %6i, t: %6.2f sec\n", #op, k, dUserTime); \
}
/* Tests wNAF computation. Non-adjacent-form is discussed in the paper: D.
* Hankerson, J. Hernandez and A. Menezes, "Software implementation of
* elliptic curve cryptography over binary fields", Proc. CHES 2000. */
mp_err
main(void)
{
signed char naf[BITSIZE + 1];
ECGroup *group = NULL;
mp_int k;
mp_int *scalar;
int i, count;
int res;
int w = 5;
char s[1000];
/* Get a 160 bit scalar to compute wNAF from */
group = ECGroup_fromName(ECCurve_SECG_PRIME_160R1);
scalar = &group->genx;
/* Compute wNAF representation of scalar */
ec_compute_wNAF(naf, BITSIZE, scalar, w);
/* Verify correctness of representation */
mp_init(&k); /* init k to 0 */
for (i = BITSIZE; i >= 0; i--) {
mp_add(&k, &k, &k);
/* digits in mp_???_d are unsigned */
if (naf[i] >= 0) {
mp_add_d(&k, naf[i], &k);
} else {
mp_sub_d(&k, -naf[i], &k);
}
}
if (mp_cmp(&k, scalar) != 0) {
printf("Error: incorrect NAF value.\n");
MP_CHECKOK(mp_toradix(&k, s, 16));
printf("NAF value %s\n", s);
MP_CHECKOK(mp_toradix(scalar, s, 16));
printf("original value %s\n", s);
goto CLEANUP;
}
/* Verify digits of representation are valid */
for (i = 0; i <= BITSIZE; i++) {
if (naf[i] % 2 == 0 && naf[i] != 0) {
printf("Error: Even non-zero digit found.\n");
goto CLEANUP;
}
if (naf[i] < -(ec_twoTo(w - 1)) || naf[i] >= ec_twoTo(w - 1)) {
printf("Error: Magnitude of naf digit too large.\n");
goto CLEANUP;
}
}
/* Verify sparsity of representation */
count = w - 1;
for (i = 0; i <= BITSIZE; i++) {
if (naf[i] != 0) {
if (count < w - 1) {
printf("Error: Sparsity failed.\n");
goto CLEANUP;
}
count = 0;
} else
count++;
}
/* Check timing */
M_TimeOperation(ec_compute_wNAF(naf, BITSIZE, scalar, w), 10000);
printf("Test passed.\n");
CLEANUP:
ECGroup_free(group);
return MP_OKAY;
}

View File

@ -1,409 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mpi.h"
#include "mplogic.h"
#include "mpprime.h"
#include "ecl.h"
#include "ecl-curve.h"
#include "ecp.h"
#include <stdio.h>
#include <strings.h>
#include <assert.h>
#include <time.h>
#include <sys/time.h>
#include <sys/resource.h>
/* Time k repetitions of operation op. */
#define M_TimeOperation(op, k) \
{ \
double dStart, dNow, dUserTime; \
struct rusage ru; \
int i; \
getrusage(RUSAGE_SELF, &ru); \
dStart = (double)ru.ru_utime.tv_sec + (double)ru.ru_utime.tv_usec * 0.000001; \
for (i = 0; i < k; i++) { \
{ \
op; \
} \
}; \
getrusage(RUSAGE_SELF, &ru); \
dNow = (double)ru.ru_utime.tv_sec + (double)ru.ru_utime.tv_usec * 0.000001; \
dUserTime = dNow - dStart; \
if (dUserTime) \
printf(" %-45s k: %6i, t: %6.2f sec\n", #op, k, dUserTime); \
}
/* Test curve using generic field arithmetic. */
#define ECTEST_GENERIC_GFP(name_c, name) \
printf("Testing %s using generic implementation...\n", name_c); \
params = EC_GetNamedCurveParams(name); \
if (params == NULL) { \
printf(" Error: could not construct params.\n"); \
res = MP_NO; \
goto CLEANUP; \
} \
ECGroup_free(group); \
group = ECGroup_fromHex(params); \
if (group == NULL) { \
printf(" Error: could not construct group.\n"); \
res = MP_NO; \
goto CLEANUP; \
} \
MP_CHECKOK(ectest_curve_GFp(group, ectestPrint, ectestTime, 1)); \
printf("... okay.\n");
/* Test curve using specific field arithmetic. */
#define ECTEST_NAMED_GFP(name_c, name) \
printf("Testing %s using specific implementation...\n", name_c); \
ECGroup_free(group); \
group = ECGroup_fromName(name); \
if (group == NULL) { \
printf(" Warning: could not construct group.\n"); \
printf("... failed; continuing with remaining tests.\n"); \
} else { \
MP_CHECKOK(ectest_curve_GFp(group, ectestPrint, ectestTime, 0)); \
printf("... okay.\n"); \
}
/* Performs basic tests of elliptic curve cryptography over prime fields.
* If tests fail, then it prints an error message, aborts, and returns an
* error code. Otherwise, returns 0. */
int
ectest_curve_GFp(ECGroup *group, int ectestPrint, int ectestTime,
int generic)
{
mp_int one, order_1, gx, gy, rx, ry, n;
int size;
mp_err res;
char s[1000];
/* initialize values */
MP_CHECKOK(mp_init(&one));
MP_CHECKOK(mp_init(&order_1));
MP_CHECKOK(mp_init(&gx));
MP_CHECKOK(mp_init(&gy));
MP_CHECKOK(mp_init(&rx));
MP_CHECKOK(mp_init(&ry));
MP_CHECKOK(mp_init(&n));
MP_CHECKOK(mp_set_int(&one, 1));
MP_CHECKOK(mp_sub(&group->order, &one, &order_1));
/* encode base point */
if (group->meth->field_dec) {
MP_CHECKOK(group->meth->field_dec(&group->genx, &gx, group->meth));
MP_CHECKOK(group->meth->field_dec(&group->geny, &gy, group->meth));
} else {
MP_CHECKOK(mp_copy(&group->genx, &gx));
MP_CHECKOK(mp_copy(&group->geny, &gy));
}
if (ectestPrint) {
/* output base point */
printf(" base point P:\n");
MP_CHECKOK(mp_toradix(&gx, s, 16));
printf(" %s\n", s);
MP_CHECKOK(mp_toradix(&gy, s, 16));
printf(" %s\n", s);
if (group->meth->field_enc) {
printf(" base point P (encoded):\n");
MP_CHECKOK(mp_toradix(&group->genx, s, 16));
printf(" %s\n", s);
MP_CHECKOK(mp_toradix(&group->geny, s, 16));
printf(" %s\n", s);
}
}
#ifdef ECL_ENABLE_GFP_PT_MUL_AFF
/* multiply base point by order - 1 and check for negative of base
* point */
MP_CHECKOK(ec_GFp_pt_mul_aff(&order_1, &group->genx, &group->geny, &rx, &ry, group));
if (ectestPrint) {
printf(" (order-1)*P (affine):\n");
MP_CHECKOK(mp_toradix(&rx, s, 16));
printf(" %s\n", s);
MP_CHECKOK(mp_toradix(&ry, s, 16));
printf(" %s\n", s);
}
MP_CHECKOK(group->meth->field_neg(&ry, &ry, group->meth));
if ((mp_cmp(&rx, &group->genx) != 0) || (mp_cmp(&ry, &group->geny) != 0)) {
printf(" Error: invalid result (expected (- base point)).\n");
res = MP_NO;
goto CLEANUP;
}
#endif
#ifdef ECL_ENABLE_GFP_PT_MUL_AFF
/* multiply base point by order - 1 and check for negative of base
* point */
MP_CHECKOK(ec_GFp_pt_mul_jac(&order_1, &group->genx, &group->geny, &rx, &ry, group));
if (ectestPrint) {
printf(" (order-1)*P (jacobian):\n");
MP_CHECKOK(mp_toradix(&rx, s, 16));
printf(" %s\n", s);
MP_CHECKOK(mp_toradix(&ry, s, 16));
printf(" %s\n", s);
}
MP_CHECKOK(group->meth->field_neg(&ry, &ry, group->meth));
if ((mp_cmp(&rx, &group->genx) != 0) || (mp_cmp(&ry, &group->geny) != 0)) {
printf(" Error: invalid result (expected (- base point)).\n");
res = MP_NO;
goto CLEANUP;
}
#endif
/* multiply base point by order - 1 and check for negative of base
* point */
MP_CHECKOK(ECPoint_mul(group, &order_1, NULL, NULL, &rx, &ry));
if (ectestPrint) {
printf(" (order-1)*P (ECPoint_mul):\n");
MP_CHECKOK(mp_toradix(&rx, s, 16));
printf(" %s\n", s);
MP_CHECKOK(mp_toradix(&ry, s, 16));
printf(" %s\n", s);
}
MP_CHECKOK(mp_submod(&group->meth->irr, &ry, &group->meth->irr, &ry));
if ((mp_cmp(&rx, &gx) != 0) || (mp_cmp(&ry, &gy) != 0)) {
printf(" Error: invalid result (expected (- base point)).\n");
res = MP_NO;
goto CLEANUP;
}
/* multiply base point by order - 1 and check for negative of base
* point */
MP_CHECKOK(ECPoint_mul(group, &order_1, &gx, &gy, &rx, &ry));
if (ectestPrint) {
printf(" (order-1)*P (ECPoint_mul):\n");
MP_CHECKOK(mp_toradix(&rx, s, 16));
printf(" %s\n", s);
MP_CHECKOK(mp_toradix(&ry, s, 16));
printf(" %s\n", s);
}
MP_CHECKOK(mp_submod(&group->meth->irr, &ry, &group->meth->irr, &ry));
if ((mp_cmp(&rx, &gx) != 0) || (mp_cmp(&ry, &gy) != 0)) {
printf(" Error: invalid result (expected (- base point)).\n");
res = MP_NO;
goto CLEANUP;
}
#ifdef ECL_ENABLE_GFP_PT_MUL_AFF
/* multiply base point by order and check for point at infinity */
MP_CHECKOK(ec_GFp_pt_mul_aff(&group->order, &group->genx, &group->geny, &rx, &ry,
group));
if (ectestPrint) {
printf(" (order)*P (affine):\n");
MP_CHECKOK(mp_toradix(&rx, s, 16));
printf(" %s\n", s);
MP_CHECKOK(mp_toradix(&ry, s, 16));
printf(" %s\n", s);
}
if (ec_GFp_pt_is_inf_aff(&rx, &ry) != MP_YES) {
printf(" Error: invalid result (expected point at infinity).\n");
res = MP_NO;
goto CLEANUP;
}
#endif
#ifdef ECL_ENABLE_GFP_PT_MUL_JAC
/* multiply base point by order and check for point at infinity */
MP_CHECKOK(ec_GFp_pt_mul_jac(&group->order, &group->genx, &group->geny, &rx, &ry,
group));
if (ectestPrint) {
printf(" (order)*P (jacobian):\n");
MP_CHECKOK(mp_toradix(&rx, s, 16));
printf(" %s\n", s);
MP_CHECKOK(mp_toradix(&ry, s, 16));
printf(" %s\n", s);
}
if (ec_GFp_pt_is_inf_aff(&rx, &ry) != MP_YES) {
printf(" Error: invalid result (expected point at infinity).\n");
res = MP_NO;
goto CLEANUP;
}
#endif
/* multiply base point by order and check for point at infinity */
MP_CHECKOK(ECPoint_mul(group, &group->order, NULL, NULL, &rx, &ry));
if (ectestPrint) {
printf(" (order)*P (ECPoint_mul):\n");
MP_CHECKOK(mp_toradix(&rx, s, 16));
printf(" %s\n", s);
MP_CHECKOK(mp_toradix(&ry, s, 16));
printf(" %s\n", s);
}
if (ec_GFp_pt_is_inf_aff(&rx, &ry) != MP_YES) {
printf(" Error: invalid result (expected point at infinity).\n");
res = MP_NO;
goto CLEANUP;
}
/* multiply base point by order and check for point at infinity */
MP_CHECKOK(ECPoint_mul(group, &group->order, &gx, &gy, &rx, &ry));
if (ectestPrint) {
printf(" (order)*P (ECPoint_mul):\n");
MP_CHECKOK(mp_toradix(&rx, s, 16));
printf(" %s\n", s);
MP_CHECKOK(mp_toradix(&ry, s, 16));
printf(" %s\n", s);
}
if (ec_GFp_pt_is_inf_aff(&rx, &ry) != MP_YES) {
printf(" Error: invalid result (expected point at infinity).\n");
res = MP_NO;
goto CLEANUP;
}
/* check that (order-1)P + (order-1)P + P == (order-1)P */
MP_CHECKOK(ECPoints_mul(group, &order_1, &order_1, &gx, &gy, &rx, &ry));
MP_CHECKOK(ECPoints_mul(group, &one, &one, &rx, &ry, &rx, &ry));
if (ectestPrint) {
printf(" (order-1)*P + (order-1)*P + P == (order-1)*P (ECPoints_mul):\n");
MP_CHECKOK(mp_toradix(&rx, s, 16));
printf(" %s\n", s);
MP_CHECKOK(mp_toradix(&ry, s, 16));
printf(" %s\n", s);
}
MP_CHECKOK(mp_submod(&group->meth->irr, &ry, &group->meth->irr, &ry));
if ((mp_cmp(&rx, &gx) != 0) || (mp_cmp(&ry, &gy) != 0)) {
printf(" Error: invalid result (expected (- base point)).\n");
res = MP_NO;
goto CLEANUP;
}
/* test validate_point function */
if (ECPoint_validate(group, &gx, &gy) != MP_YES) {
printf(" Error: validate point on base point failed.\n");
res = MP_NO;
goto CLEANUP;
}
MP_CHECKOK(mp_add_d(&gy, 1, &ry));
if (ECPoint_validate(group, &gx, &ry) != MP_NO) {
printf(" Error: validate point on invalid point passed.\n");
res = MP_NO;
goto CLEANUP;
}
if (ectestTime) {
/* compute random scalar */
size = mpl_significant_bits(&group->meth->irr);
if (size < MP_OKAY) {
goto CLEANUP;
}
MP_CHECKOK(mpp_random_size(&n, (size + ECL_BITS - 1) / ECL_BITS));
MP_CHECKOK(group->meth->field_mod(&n, &n, group->meth));
/* timed test */
if (generic) {
#ifdef ECL_ENABLE_GFP_PT_MUL_AFF
M_TimeOperation(MP_CHECKOK(ec_GFp_pt_mul_aff(&n, &group->genx, &group->geny, &rx, &ry,
group)),
100);
#endif
M_TimeOperation(MP_CHECKOK(ECPoint_mul(group, &n, NULL, NULL, &rx, &ry)),
100);
M_TimeOperation(MP_CHECKOK(ECPoints_mul(group, &n, &n, &gx, &gy, &rx, &ry)), 100);
} else {
M_TimeOperation(MP_CHECKOK(ECPoint_mul(group, &n, NULL, NULL, &rx, &ry)),
100);
M_TimeOperation(MP_CHECKOK(ECPoint_mul(group, &n, &gx, &gy, &rx, &ry)),
100);
M_TimeOperation(MP_CHECKOK(ECPoints_mul(group, &n, &n, &gx, &gy, &rx, &ry)), 100);
}
}
CLEANUP:
mp_clear(&one);
mp_clear(&order_1);
mp_clear(&gx);
mp_clear(&gy);
mp_clear(&rx);
mp_clear(&ry);
mp_clear(&n);
if (res != MP_OKAY) {
printf(" Error: exiting with error value %i\n", res);
}
return res;
}
/* Prints help information. */
void
printUsage()
{
printf("Usage: ecp_test [--print] [--time]\n");
printf(" --print Print out results of each point arithmetic test.\n");
printf(" --time Benchmark point operations and print results.\n");
}
/* Performs tests of elliptic curve cryptography over prime fields If
* tests fail, then it prints an error message, aborts, and returns an
* error code. Otherwise, returns 0. */
int
main(int argv, char **argc)
{
int ectestTime = 0;
int ectestPrint = 0;
int i;
ECGroup *group = NULL;
ECCurveParams *params = NULL;
mp_err res;
/* read command-line arguments */
for (i = 1; i < argv; i++) {
if ((strcasecmp(argc[i], "time") == 0) || (strcasecmp(argc[i], "-time") == 0) || (strcasecmp(argc[i], "--time") == 0)) {
ectestTime = 1;
} else if ((strcasecmp(argc[i], "print") == 0) || (strcasecmp(argc[i], "-print") == 0) || (strcasecmp(argc[i], "--print") == 0)) {
ectestPrint = 1;
} else {
printUsage();
return 0;
}
}
/* generic arithmetic tests */
ECTEST_GENERIC_GFP("SECP-160R1", ECCurve_SECG_PRIME_160R1);
/* specific arithmetic tests */
ECTEST_NAMED_GFP("NIST-P192", ECCurve_NIST_P192);
ECTEST_NAMED_GFP("NIST-P224", ECCurve_NIST_P224);
ECTEST_NAMED_GFP("NIST-P256", ECCurve_NIST_P256);
ECTEST_NAMED_GFP("NIST-P384", ECCurve_NIST_P384);
ECTEST_NAMED_GFP("NIST-P521", ECCurve_NIST_P521);
ECTEST_NAMED_GFP("ANSI X9.62 PRIME192v1", ECCurve_X9_62_PRIME_192V1);
ECTEST_NAMED_GFP("ANSI X9.62 PRIME192v2", ECCurve_X9_62_PRIME_192V2);
ECTEST_NAMED_GFP("ANSI X9.62 PRIME192v3", ECCurve_X9_62_PRIME_192V3);
ECTEST_NAMED_GFP("ANSI X9.62 PRIME239v1", ECCurve_X9_62_PRIME_239V1);
ECTEST_NAMED_GFP("ANSI X9.62 PRIME239v2", ECCurve_X9_62_PRIME_239V2);
ECTEST_NAMED_GFP("ANSI X9.62 PRIME239v3", ECCurve_X9_62_PRIME_239V3);
ECTEST_NAMED_GFP("ANSI X9.62 PRIME256v1", ECCurve_X9_62_PRIME_256V1);
ECTEST_NAMED_GFP("SECP-112R1", ECCurve_SECG_PRIME_112R1);
ECTEST_NAMED_GFP("SECP-112R2", ECCurve_SECG_PRIME_112R2);
ECTEST_NAMED_GFP("SECP-128R1", ECCurve_SECG_PRIME_128R1);
ECTEST_NAMED_GFP("SECP-128R2", ECCurve_SECG_PRIME_128R2);
ECTEST_NAMED_GFP("SECP-160K1", ECCurve_SECG_PRIME_160K1);
ECTEST_NAMED_GFP("SECP-160R1", ECCurve_SECG_PRIME_160R1);
ECTEST_NAMED_GFP("SECP-160R2", ECCurve_SECG_PRIME_160R2);
ECTEST_NAMED_GFP("SECP-192K1", ECCurve_SECG_PRIME_192K1);
ECTEST_NAMED_GFP("SECP-192R1", ECCurve_SECG_PRIME_192R1);
ECTEST_NAMED_GFP("SECP-224K1", ECCurve_SECG_PRIME_224K1);
ECTEST_NAMED_GFP("SECP-224R1", ECCurve_SECG_PRIME_224R1);
ECTEST_NAMED_GFP("SECP-256K1", ECCurve_SECG_PRIME_256K1);
ECTEST_NAMED_GFP("SECP-256R1", ECCurve_SECG_PRIME_256R1);
ECTEST_NAMED_GFP("SECP-384R1", ECCurve_SECG_PRIME_384R1);
ECTEST_NAMED_GFP("SECP-521R1", ECCurve_SECG_PRIME_521R1);
ECTEST_NAMED_GFP("WTLS-6 (112)", ECCurve_WTLS_6);
ECTEST_NAMED_GFP("WTLS-7 (160)", ECCurve_WTLS_7);
ECTEST_NAMED_GFP("WTLS-8 (112)", ECCurve_WTLS_8);
ECTEST_NAMED_GFP("WTLS-9 (160)", ECCurve_WTLS_9);
ECTEST_NAMED_GFP("WTLS-12 (224)", ECCurve_WTLS_12);
ECTEST_NAMED_GFP("Curve25519", ECCurve25519);
CLEANUP:
EC_FreeCurveParams(params);
ECGroup_free(group);
if (res != MP_OKAY) {
printf("Error: exiting with error value %i\n", res);
}
return res;
}

View File

@ -104,6 +104,10 @@
'<(DEPTH)/lib/util/util.gyp:nssutil3',
],
}],
]
}],
[ 'OS=="linux" or OS=="android"', {
'conditions': [
[ 'target_arch=="x64"', {
'sources': [
'arcfour-amd64-gas.s',
@ -142,7 +146,7 @@
}],
],
}, {
# not Linux
# not Linux or Android
'conditions': [
[ 'moz_fold_libs==0', {
'dependencies': [
@ -221,7 +225,7 @@
}],
],
}],
[ 'fuzz==1', {
[ 'fuzz_tls==1', {
'sources': [
'det_rng.c',
],
@ -229,7 +233,7 @@
'UNSAFE_FUZZER_MODE',
],
}],
[ 'test_build==1', {
[ 'ct_verif==1', {
'defines': [
'CT_VERIF',
],
@ -374,6 +378,10 @@
'FREEBL_NO_DEPEND',
],
}],
],
}],
[ 'OS=="linux" or OS=="android"', {
'conditions': [
[ 'target_arch=="x64"', {
'defines': [
'MP_IS_LITTLE_ENDIAN',
@ -383,7 +391,7 @@
'NSS_USE_COMBA',
],
}],
[ 'target_arch=="x64" and use_msan==0', {
[ 'target_arch=="x64"', {
'defines': [
'USE_HW_AES',
'INTEL_GCM',
@ -406,7 +414,7 @@
'SHA_NO_LONG_LONG',
],
}],
[ 'target_arch=="arm64"', {
[ 'target_arch=="arm64" or target_arch=="aarch64"', {
'defines': [
'NSS_USE_64',
],

View File

@ -1,334 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#define INCL_DOS
#define INCL_DOSERRORS
#include <os2.h>
#include "secrng.h"
#include "prerror.h"
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
#include <sys/stat.h>
static BOOL
clockTickTime(unsigned long *phigh, unsigned long *plow)
{
APIRET rc = NO_ERROR;
QWORD qword = { 0, 0 };
rc = DosTmrQueryTime(&qword);
if (rc != NO_ERROR)
return FALSE;
*phigh = qword.ulHi;
*plow = qword.ulLo;
return TRUE;
}
size_t
RNG_GetNoise(void *buf, size_t maxbuf)
{
unsigned long high = 0;
unsigned long low = 0;
clock_t val = 0;
int n = 0;
int nBytes = 0;
time_t sTime;
if (maxbuf <= 0)
return 0;
clockTickTime(&high, &low);
/* get the maximally changing bits first */
nBytes = sizeof(low) > maxbuf ? maxbuf : sizeof(low);
memcpy(buf, &low, nBytes);
n += nBytes;
maxbuf -= nBytes;
if (maxbuf <= 0)
return n;
nBytes = sizeof(high) > maxbuf ? maxbuf : sizeof(high);
memcpy(((char *)buf) + n, &high, nBytes);
n += nBytes;
maxbuf -= nBytes;
if (maxbuf <= 0)
return n;
/* get the number of milliseconds that have elapsed since application started */
val = clock();
nBytes = sizeof(val) > maxbuf ? maxbuf : sizeof(val);
memcpy(((char *)buf) + n, &val, nBytes);
n += nBytes;
maxbuf -= nBytes;
if (maxbuf <= 0)
return n;
/* get the time in seconds since midnight Jan 1, 1970 */
time(&sTime);
nBytes = sizeof(sTime) > maxbuf ? maxbuf : sizeof(sTime);
memcpy(((char *)buf) + n, &sTime, nBytes);
n += nBytes;
return n;
}
static BOOL
EnumSystemFiles(void (*func)(const char *))
{
APIRET rc;
ULONG sysInfo = 0;
char bootLetter[2];
char sysDir[_MAX_PATH] = "";
char filename[_MAX_PATH];
HDIR hdir = HDIR_CREATE;
ULONG numFiles = 1;
FILEFINDBUF3 fileBuf = { 0 };
ULONG buflen = sizeof(FILEFINDBUF3);
if (DosQuerySysInfo(QSV_BOOT_DRIVE, QSV_BOOT_DRIVE, (PVOID)&sysInfo,
sizeof(ULONG)) == NO_ERROR) {
bootLetter[0] = sysInfo + 'A' - 1;
bootLetter[1] = '\0';
strcpy(sysDir, bootLetter);
strcpy(sysDir + 1, ":\\OS2\\");
strcpy(filename, sysDir);
strcat(filename, "*.*");
}
rc = DosFindFirst(filename, &hdir, FILE_NORMAL, &fileBuf, buflen,
&numFiles, FIL_STANDARD);
if (rc == NO_ERROR) {
do {
// pass the full pathname to the callback
sprintf(filename, "%s%s", sysDir, fileBuf.achName);
(*func)(filename);
numFiles = 1;
rc = DosFindNext(hdir, &fileBuf, buflen, &numFiles);
if (rc != NO_ERROR && rc != ERROR_NO_MORE_FILES)
printf("DosFindNext errod code = %d\n", rc);
} while (rc == NO_ERROR);
rc = DosFindClose(hdir);
if (rc != NO_ERROR)
printf("DosFindClose error code = %d", rc);
} else
printf("DosFindFirst error code = %d", rc);
return TRUE;
}
static int dwNumFiles, dwReadEvery, dwFileToRead = 0;
static void
CountFiles(const char *file)
{
dwNumFiles++;
}
static void
ReadFiles(const char *file)
{
if ((dwNumFiles % dwReadEvery) == 0)
RNG_FileForRNG(file);
dwNumFiles++;
}
static void
ReadSingleFile(const char *filename)
{
unsigned char buffer[1024];
FILE *file;
file = fopen((char *)filename, "rb");
if (file != NULL) {
while (fread(buffer, 1, sizeof(buffer), file) > 0)
;
fclose(file);
}
}
static void
ReadOneFile(const char *file)
{
if (dwNumFiles == dwFileToRead) {
ReadSingleFile(file);
}
dwNumFiles++;
}
static void
ReadSystemFiles(void)
{
// first count the number of files
dwNumFiles = 0;
if (!EnumSystemFiles(CountFiles))
return;
RNG_RandomUpdate(&dwNumFiles, sizeof(dwNumFiles));
// now read 10 files
if (dwNumFiles == 0)
return;
dwReadEvery = dwNumFiles / 10;
if (dwReadEvery == 0)
dwReadEvery = 1; // less than 10 files
dwNumFiles = 0;
EnumSystemFiles(ReadFiles);
}
void
RNG_SystemInfoForRNG(void)
{
unsigned long *plong = 0;
PTIB ptib;
PPIB ppib;
APIRET rc = NO_ERROR;
DATETIME dt;
COUNTRYCODE cc = { 0 };
COUNTRYINFO ci = { 0 };
unsigned long actual = 0;
char path[_MAX_PATH] = "";
char fullpath[_MAX_PATH] = "";
unsigned long pathlength = sizeof(path);
FSALLOCATE fsallocate;
FILESTATUS3 fstatus;
unsigned long defaultdrive = 0;
unsigned long logicaldrives = 0;
unsigned long sysInfo[QSV_MAX] = { 0 };
char buffer[20];
int nBytes = 0;
nBytes = RNG_GetNoise(buffer, sizeof(buffer));
RNG_RandomUpdate(buffer, nBytes);
/* allocate memory and use address and memory */
plong = (unsigned long *)malloc(sizeof(*plong));
RNG_RandomUpdate(&plong, sizeof(plong));
RNG_RandomUpdate(plong, sizeof(*plong));
free(plong);
/* process info */
rc = DosGetInfoBlocks(&ptib, &ppib);
if (rc == NO_ERROR) {
RNG_RandomUpdate(ptib, sizeof(*ptib));
RNG_RandomUpdate(ppib, sizeof(*ppib));
}
/* time */
rc = DosGetDateTime(&dt);
if (rc == NO_ERROR) {
RNG_RandomUpdate(&dt, sizeof(dt));
}
/* country */
rc = DosQueryCtryInfo(sizeof(ci), &cc, &ci, &actual);
if (rc == NO_ERROR) {
RNG_RandomUpdate(&cc, sizeof(cc));
RNG_RandomUpdate(&ci, sizeof(ci));
RNG_RandomUpdate(&actual, sizeof(actual));
}
/* current directory */
rc = DosQueryCurrentDir(0, path, &pathlength);
strcat(fullpath, "\\");
strcat(fullpath, path);
if (rc == NO_ERROR) {
RNG_RandomUpdate(fullpath, strlen(fullpath));
// path info
rc = DosQueryPathInfo(fullpath, FIL_STANDARD, &fstatus, sizeof(fstatus));
if (rc == NO_ERROR) {
RNG_RandomUpdate(&fstatus, sizeof(fstatus));
}
}
/* file system info */
rc = DosQueryFSInfo(0, FSIL_ALLOC, &fsallocate, sizeof(fsallocate));
if (rc == NO_ERROR) {
RNG_RandomUpdate(&fsallocate, sizeof(fsallocate));
}
/* drive info */
rc = DosQueryCurrentDisk(&defaultdrive, &logicaldrives);
if (rc == NO_ERROR) {
RNG_RandomUpdate(&defaultdrive, sizeof(defaultdrive));
RNG_RandomUpdate(&logicaldrives, sizeof(logicaldrives));
}
/* system info */
rc = DosQuerySysInfo(1L, QSV_MAX, (PVOID)&sysInfo, sizeof(ULONG) * QSV_MAX);
if (rc == NO_ERROR) {
RNG_RandomUpdate(&sysInfo, sizeof(sysInfo));
}
// now let's do some files
ReadSystemFiles();
/* more noise */
nBytes = RNG_GetNoise(buffer, sizeof(buffer));
RNG_RandomUpdate(buffer, nBytes);
}
void
RNG_FileForRNG(const char *filename)
{
struct stat stat_buf;
unsigned char buffer[1024];
FILE *file = 0;
int nBytes = 0;
static int totalFileBytes = 0;
if (stat((char *)filename, &stat_buf) < 0)
return;
RNG_RandomUpdate((unsigned char *)&stat_buf, sizeof(stat_buf));
file = fopen((char *)filename, "r");
if (file != NULL) {
for (;;) {
size_t bytes = fread(buffer, 1, sizeof(buffer), file);
if (bytes == 0)
break;
RNG_RandomUpdate(buffer, bytes);
totalFileBytes += bytes;
if (totalFileBytes > 250000)
break;
}
fclose(file);
}
nBytes = RNG_GetNoise(buffer, 20);
RNG_RandomUpdate(buffer, nBytes);
}
static void
rng_systemJitter(void)
{
dwNumFiles = 0;
EnumSystemFiles(ReadOneFile);
dwFileToRead++;
if (dwFileToRead >= dwNumFiles) {
dwFileToRead = 0;
}
}
size_t
RNG_SystemRNG(void *dest, size_t maxLen)
{
return rng_systemFromNoise(dest, maxLen);
}

View File

@ -8,42 +8,9 @@
#include "seccomon.h"
#ifndef XP_WIN
static size_t rng_systemFromNoise(unsigned char *dest, size_t maxLen);
#endif
#if defined(XP_UNIX) || defined(XP_BEOS)
#include "unix_rand.c"
#endif
#ifdef XP_WIN
#include "win_rand.c"
#endif
#ifdef XP_OS2
#include "os2_rand.c"
#endif
#ifndef XP_WIN
/*
* Normal RNG_SystemRNG() isn't available, use the system noise to collect
* the required amount of entropy.
*/
static size_t
rng_systemFromNoise(unsigned char *dest, size_t maxLen)
{
size_t retBytes = maxLen;
while (maxLen) {
size_t nbytes = RNG_GetNoise(dest, maxLen);
PORT_Assert(nbytes != 0);
dest += nbytes;
maxLen -= nbytes;
/* some hw op to try to introduce more entropy into the next
* RNG_GetNoise call */
rng_systemJitter();
}
return retBytes;
}
#endif

View File

@ -894,6 +894,9 @@ RNG_SystemInfoForRNG(void)
/* grab some data from system's PRNG before any other files. */
bytes = RNG_FileUpdate("/dev/urandom", SYSTEM_RNG_SEED_COUNT);
if (!bytes) {
PORT_SetError(SEC_ERROR_NEED_RANDOM);
}
/* If the user points us to a random file, pass it through the rng */
randfile = PR_GetEnvSecure("NSRANDFILE");
@ -1022,20 +1025,6 @@ RNG_FileForRNG(const char *fileName)
RNG_FileUpdate(fileName, TOTAL_FILE_LIMIT);
}
void
ReadSingleFile(const char *fileName)
{
FILE *file;
unsigned char buffer[BUFSIZ];
file = fopen(fileName, "rb");
if (file != NULL) {
while (fread(buffer, 1, sizeof(buffer), file) > 0)
;
fclose(file);
}
}
#define _POSIX_PTHREAD_SEMANTICS
#include <dirent.h>
@ -1055,89 +1044,6 @@ ReadFileOK(char *dir, char *file)
return S_ISREG(stat_buf.st_mode) ? PR_TRUE : PR_FALSE;
}
/*
* read one file out of either /etc or the user's home directory.
* fileToRead tells which file to read.
*
* return 1 if it's time to reset the fileToRead (no more files to read).
*/
static int
ReadOneFile(int fileToRead)
{
char *dir = "/etc";
DIR *fd = opendir(dir);
int resetCount = 0;
struct dirent *entry;
#if defined(__sun)
char firstName[256];
#else
char firstName[NAME_MAX + 1];
#endif
const char *name = NULL;
int i;
if (fd == NULL) {
dir = PR_GetEnvSecure("HOME");
if (dir) {
fd = opendir(dir);
}
}
if (fd == NULL) {
return 1;
}
firstName[0] = '\0';
for (i = 0; i <= fileToRead; i++) {
do {
/* readdir() isn't guaranteed to be thread safe on every platform;
* this code assumes the same directory isn't read concurrently.
* This usage is confirmed safe on Linux, see bug 1254334. */
entry = readdir(fd);
} while (entry != NULL && !ReadFileOK(dir, &entry->d_name[0]));
if (entry == NULL) {
resetCount = 1; /* read to the end, start again at the beginning */
if (firstName[0]) {
/* ran out of entries in the directory, use the first one */
name = firstName;
}
break;
}
name = entry->d_name;
if (i == 0) {
/* copy the name of the first in case we run out of entries */
PORT_Assert(PORT_Strlen(name) < sizeof(firstName));
PORT_Strncpy(firstName, name, sizeof(firstName) - 1);
firstName[sizeof(firstName) - 1] = '\0';
}
}
if (name) {
char filename[PATH_MAX];
int count = snprintf(filename, sizeof(filename), "%s/%s", dir, name);
if (count >= 1) {
ReadSingleFile(filename);
}
}
closedir(fd);
return resetCount;
}
/*
* do something to try to introduce more noise into the 'GetNoise' call
*/
static void
rng_systemJitter(void)
{
static int fileToRead = 1;
if (ReadOneFile(fileToRead)) {
fileToRead = 1;
} else {
fileToRead++;
}
}
size_t
RNG_SystemRNG(void *dest, size_t maxLen)
{
@ -1149,7 +1055,8 @@ RNG_SystemRNG(void *dest, size_t maxLen)
file = fopen("/dev/urandom", "r");
if (file == NULL) {
return rng_systemFromNoise(dest, maxLen);
PORT_SetError(SEC_ERROR_NEED_RANDOM);
return 0;
}
/* Read from the underlying file descriptor directly to bypass stdio
* buffering and avoid reading more bytes than we need from /dev/urandom.

View File

@ -47,7 +47,10 @@ NSS_IMPLEMENT PRStatus
NSSCryptoContext_Destroy(NSSCryptoContext *cc)
{
PRStatus status = PR_SUCCESS;
PORT_Assert(cc->certStore);
PORT_Assert(cc && cc->certStore);
if (!cc) {
return PR_FAILURE;
}
if (cc->certStore) {
status = nssCertificateStore_Destroy(cc->certStore);
if (status == PR_FAILURE) {
@ -93,8 +96,8 @@ NSSCryptoContext_FindOrImportCertificate(
{
NSSCertificate *rvCert = NULL;
PORT_Assert(cc->certStore);
if (!cc->certStore) {
PORT_Assert(cc && cc->certStore);
if (!cc || !cc->certStore) {
nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
return rvCert;
}
@ -146,8 +149,8 @@ nssCryptoContext_ImportTrust(
NSSTrust *trust)
{
PRStatus nssrv;
PORT_Assert(cc->certStore);
if (!cc->certStore) {
PORT_Assert(cc && cc->certStore);
if (!cc || !cc->certStore) {
return PR_FAILURE;
}
nssrv = nssCertificateStore_AddTrust(cc->certStore, trust);
@ -165,8 +168,8 @@ nssCryptoContext_ImportSMIMEProfile(
nssSMIMEProfile *profile)
{
PRStatus nssrv;
PORT_Assert(cc->certStore);
if (!cc->certStore) {
PORT_Assert(cc && cc->certStore);
if (!cc || !cc->certStore) {
return PR_FAILURE;
}
nssrv = nssCertificateStore_AddSMIMEProfile(cc->certStore, profile);
@ -189,8 +192,8 @@ NSSCryptoContext_FindBestCertificateByNickname(
{
NSSCertificate **certs;
NSSCertificate *rvCert = NULL;
PORT_Assert(cc->certStore);
if (!cc->certStore) {
PORT_Assert(cc && cc->certStore);
if (!cc || !cc->certStore) {
return NULL;
}
certs = nssCertificateStore_FindCertificatesByNickname(cc->certStore,
@ -215,8 +218,8 @@ NSSCryptoContext_FindCertificatesByNickname(
NSSArena *arenaOpt)
{
NSSCertificate **rvCerts;
PORT_Assert(cc->certStore);
if (!cc->certStore) {
PORT_Assert(cc && cc->certStore);
if (!cc || !cc->certStore) {
return NULL;
}
rvCerts = nssCertificateStore_FindCertificatesByNickname(cc->certStore,
@ -233,8 +236,8 @@ NSSCryptoContext_FindCertificateByIssuerAndSerialNumber(
NSSDER *issuer,
NSSDER *serialNumber)
{
PORT_Assert(cc->certStore);
if (!cc->certStore) {
PORT_Assert(cc && cc->certStore);
if (!cc || !cc->certStore) {
return NULL;
}
return nssCertificateStore_FindCertificateByIssuerAndSerialNumber(
@ -253,8 +256,8 @@ NSSCryptoContext_FindBestCertificateBySubject(
{
NSSCertificate **certs;
NSSCertificate *rvCert = NULL;
PORT_Assert(cc->certStore);
if (!cc->certStore) {
PORT_Assert(cc && cc->certStore);
if (!cc || !cc->certStore) {
return NULL;
}
certs = nssCertificateStore_FindCertificatesBySubject(cc->certStore,
@ -279,8 +282,8 @@ nssCryptoContext_FindCertificatesBySubject(
NSSArena *arenaOpt)
{
NSSCertificate **rvCerts;
PORT_Assert(cc->certStore);
if (!cc->certStore) {
PORT_Assert(cc && cc->certStore);
if (!cc || !cc->certStore) {
return NULL;
}
rvCerts = nssCertificateStore_FindCertificatesBySubject(cc->certStore,
@ -333,8 +336,8 @@ NSSCryptoContext_FindCertificateByEncodedCertificate(
NSSCryptoContext *cc,
NSSBER *encodedCertificate)
{
PORT_Assert(cc->certStore);
if (!cc->certStore) {
PORT_Assert(cc && cc->certStore);
if (!cc || !cc->certStore) {
return NULL;
}
return nssCertificateStore_FindCertificateByEncodedCertificate(
@ -353,8 +356,8 @@ NSSCryptoContext_FindBestCertificateByEmail(
NSSCertificate **certs;
NSSCertificate *rvCert = NULL;
PORT_Assert(cc->certStore);
if (!cc->certStore) {
PORT_Assert(cc && cc->certStore);
if (!cc || !cc->certStore) {
return NULL;
}
certs = nssCertificateStore_FindCertificatesByEmail(cc->certStore,
@ -379,8 +382,8 @@ NSSCryptoContext_FindCertificatesByEmail(
NSSArena *arenaOpt)
{
NSSCertificate **rvCerts;
PORT_Assert(cc->certStore);
if (!cc->certStore) {
PORT_Assert(cc && cc->certStore);
if (!cc || !cc->certStore) {
return NULL;
}
rvCerts = nssCertificateStore_FindCertificatesByEmail(cc->certStore,
@ -488,8 +491,8 @@ nssCryptoContext_FindTrustForCertificate(
NSSCryptoContext *cc,
NSSCertificate *cert)
{
PORT_Assert(cc->certStore);
if (!cc->certStore) {
PORT_Assert(cc && cc->certStore);
if (!cc || !cc->certStore) {
return NULL;
}
return nssCertificateStore_FindTrustForCertificate(cc->certStore, cert);
@ -500,8 +503,8 @@ nssCryptoContext_FindSMIMEProfileForCertificate(
NSSCryptoContext *cc,
NSSCertificate *cert)
{
PORT_Assert(cc->certStore);
if (!cc->certStore) {
PORT_Assert(cc && cc->certStore);
if (!cc || !cc->certStore) {
return NULL;
}
return nssCertificateStore_FindSMIMEProfileForCertificate(cc->certStore,

View File

@ -334,18 +334,12 @@ dbs_readBlob(DBS *dbsp, DBT *data)
}
len = dbs_getBlobSize(data);
mapfile = PR_CreateFileMap(filed, len, PR_PROT_READONLY);
if (mapfile == NULL) {
/* USE PR_GetError instead of PORT_GetError here
* because we are getting the error from PR_xxx
* function */
if (PR_GetError() != PR_NOT_IMPLEMENTED_ERROR) {
goto loser;
}
addr = dbs_EmulateMap(filed, len);
} else {
addr = PR_MemMap(mapfile, 0, len);
}
/* Bug 1323150
* PR_MemMap fails on Windows for larger certificates.
* https://msdn.microsoft.com/en-us/library/windows/desktop/aa366761(v=vs.85).aspx
* Let's always use the emulated map, i.e. read the file.
*/
addr = dbs_EmulateMap(filed, len);
if (addr == NULL) {
goto loser;
}

View File

@ -7267,14 +7267,6 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession,
if (mechanism == CKM_ECDH1_COFACTOR_DERIVE) {
withCofactor = PR_TRUE;
} else {
/* When not using cofactor derivation, one should
* validate the public key to avoid small subgroup
* attacks.
*/
if (EC_ValidatePublicKey(&privKey->u.ec.ecParams, &ecPoint) != SECSuccess) {
goto ec_loser;
}
}
rv = ECDH_Derive(&ecPoint, &privKey->u.ec.ecParams, &ecScalar,

View File

@ -505,3 +505,6 @@ ER3(SSL_ERROR_MALFORMED_PSK_KEY_EXCHANGE_MODES, (SSL_ERROR_BASE + 158),
ER3(SSL_ERROR_MISSING_PSK_KEY_EXCHANGE_MODES, (SSL_ERROR_BASE + 159),
"SSL expected a PSK key exchange modes extension.")
ER3(SSL_ERROR_DOWNGRADE_WITH_EARLY_DATA, (SSL_ERROR_BASE + 160),
"SSL got a pre-TLS 1.3 version even though we sent early data.")

View File

@ -63,7 +63,7 @@
'NSS_SSL_ENABLE_ZLIB',
],
}],
[ 'fuzz==1', {
[ 'fuzz_tls==1', {
'defines': [
'UNSAFE_FUZZER_MODE',
],

View File

@ -1044,8 +1044,9 @@ Null_Cipher(void *ctx, unsigned char *output, int *outputLen, int maxOutputLen,
return SECFailure;
}
*outputLen = inputLen;
if (input != output)
if (inputLen > 0 && input != output) {
PORT_Memcpy(output, input, inputLen);
}
return SECSuccess;
}
@ -3121,6 +3122,10 @@ SSL3_SendAlert(sslSocket *ss, SSL3AlertLevel level, SSL3AlertDescription desc)
{
PRUint8 bytes[2];
SECStatus rv;
PRBool needHsLock = !ssl_HaveSSL3HandshakeLock(ss);
/* Check that if I need the HS lock I also need the Xmit lock */
PORT_Assert(!needHsLock || !ssl_HaveXmitBufLock(ss));
SSL_TRC(3, ("%d: SSL3[%d]: send alert record, level=%d desc=%d",
SSL_GETPID(), ss->fd, level, desc));
@ -3128,7 +3133,9 @@ SSL3_SendAlert(sslSocket *ss, SSL3AlertLevel level, SSL3AlertDescription desc)
bytes[0] = level;
bytes[1] = desc;
ssl_GetSSL3HandshakeLock(ss);
if (needHsLock) {
ssl_GetSSL3HandshakeLock(ss);
}
if (level == alert_fatal) {
if (!ss->opt.noCache && ss->sec.ci.sid) {
ss->sec.uncache(ss->sec.ci.sid);
@ -3146,7 +3153,9 @@ SSL3_SendAlert(sslSocket *ss, SSL3AlertLevel level, SSL3AlertDescription desc)
ss->ssl3.fatalAlertSent = PR_TRUE;
}
ssl_ReleaseXmitBufLock(ss);
ssl_ReleaseSSL3HandshakeLock(ss);
if (needHsLock) {
ssl_ReleaseSSL3HandshakeLock(ss);
}
return rv; /* error set by ssl3_FlushHandshake or ssl3_SendRecord */
}
@ -6646,12 +6655,19 @@ ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
/* The server didn't pick 1.3 although we either received a
* HelloRetryRequest, or we prepared to send early app data. */
if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3 &&
(ss->ssl3.hs.helloRetry || ss->ssl3.hs.zeroRttState == ssl_0rtt_sent)) {
/* SSL3_SendAlert() will uncache the SID. */
desc = illegal_parameter;
errCode = SSL_ERROR_RX_MALFORMED_SERVER_HELLO;
goto alert_loser;
if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
if (ss->ssl3.hs.helloRetry) {
/* SSL3_SendAlert() will uncache the SID. */
desc = illegal_parameter;
errCode = SSL_ERROR_RX_MALFORMED_SERVER_HELLO;
goto alert_loser;
}
if (ss->ssl3.hs.zeroRttState == ssl_0rtt_sent) {
/* SSL3_SendAlert() will uncache the SID. */
desc = illegal_parameter;
errCode = SSL_ERROR_DOWNGRADE_WITH_EARLY_DATA;
goto alert_loser;
}
}
/* Check that the server negotiated the same version as it did
@ -8215,6 +8231,20 @@ ssl3_SelectServerCert(sslSocket *ss)
const ssl3KEADef *kea_def = ss->ssl3.hs.kea_def;
PRCList *cursor;
/* If the client didn't include the supported groups extension, assume just
* P-256 support and disable all the other ECDHE groups. This also affects
* ECDHE group selection, but this function is called first. */
if (!ssl3_ExtensionNegotiated(ss, ssl_supported_groups_xtn)) {
unsigned int i;
for (i = 0; i < SSL_NAMED_GROUP_COUNT; ++i) {
if (ss->namedGroupPreferences[i] &&
ss->namedGroupPreferences[i]->keaType == ssl_kea_ecdh &&
ss->namedGroupPreferences[i]->name != ssl_grp_ec_secp256r1) {
ss->namedGroupPreferences[i] = NULL;
}
}
}
/* This picks the first certificate that has:
* a) the right authentication method, and
* b) the right named curve (EC only)

View File

@ -32,6 +32,7 @@ ssl3_InitGather(sslGather *gs)
gs->readOffset = 0;
gs->dtlsPacketOffset = 0;
gs->dtlsPacket.len = 0;
gs->rejectV2Records = PR_FALSE;
status = sslBuffer_Grow(&gs->buf, 4096);
return status;
}
@ -147,8 +148,11 @@ ssl3_GatherData(sslSocket *ss, sslGather *gs, int flags, ssl2Gather *ssl2gs)
switch (gs->state) {
case GS_HEADER:
/* Check for SSLv2 handshakes. Always assume SSLv3 on clients,
* support SSLv2 handshakes only when ssl2gs != NULL. */
if (!ssl2gs || ssl3_isLikelyV3Hello(gs->hdr)) {
* support SSLv2 handshakes only when ssl2gs != NULL.
* Always assume v3 after we received the first record. */
if (!ssl2gs ||
ss->gs.rejectV2Records ||
ssl3_isLikelyV3Hello(gs->hdr)) {
/* Should have a non-SSLv2 record header in gs->hdr. Extract
* the length of the following encrypted data, and then
* read in the rest of the record into gs->inbuf. */
@ -183,7 +187,7 @@ ssl3_GatherData(sslSocket *ss, sslGather *gs, int flags, ssl2Gather *ssl2gs)
/* This is the max length for an encrypted SSLv3+ fragment. */
if (!v2HdrLength &&
gs->remainder > (MAX_FRAGMENT_LENGTH + 2048)) {
SSL3_SendAlert(ss, alert_fatal, unexpected_message);
SSL3_SendAlert(ss, alert_fatal, record_overflow);
gs->state = GS_INIT;
PORT_SetError(SSL_ERROR_RX_RECORD_TOO_LONG);
return SECFailure;
@ -205,13 +209,28 @@ ssl3_GatherData(sslSocket *ss, sslGather *gs, int flags, ssl2Gather *ssl2gs)
* many into the gs->hdr[] buffer. Copy them over into inbuf so
* that we can properly process the hello record later. */
if (v2HdrLength) {
/* Reject v2 records that don't even carry enough data to
* resemble a valid ClientHello header. */
if (gs->remainder < SSL_HL_CLIENT_HELLO_HBYTES) {
SSL3_SendAlert(ss, alert_fatal, illegal_parameter);
PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
return SECFailure;
}
PORT_Assert(lbp);
gs->inbuf.len = 5 - v2HdrLength;
PORT_Memcpy(lbp, gs->hdr + v2HdrLength, gs->inbuf.len);
gs->remainder -= gs->inbuf.len;
lbp += gs->inbuf.len;
}
break; /* End this case. Continue around the loop. */
if (gs->remainder > 0) {
break; /* End this case. Continue around the loop. */
}
/* FALL THROUGH if (gs->remainder == 0) as we just received
* an empty record and there's really no point in calling
* ssl_DefRecv() with buf=NULL and len=0. */
case GS_DATA:
/*
@ -219,6 +238,10 @@ ssl3_GatherData(sslSocket *ss, sslGather *gs, int flags, ssl2Gather *ssl2gs)
*/
SSL_TRC(10, ("%d: SSL[%d]: got record of %d bytes",
SSL_GETPID(), ss->fd, gs->inbuf.len));
/* reject any v2 records from now on */
ss->gs.rejectV2Records = PR_TRUE;
gs->state = GS_INIT;
return 1;
}

View File

@ -66,6 +66,8 @@ ssl_DefRecv(sslSocket *ss, unsigned char *buf, int len, int flags)
PRFileDesc *lower = ss->fd->lower;
int rv;
PORT_Assert(buf && len > 0);
rv = lower->methods->recv(lower, (void *)buf, len, flags, ss->rTimeout);
if (rv < 0) {
DEFINE_ERROR

View File

@ -244,6 +244,7 @@ typedef enum {
SSL_ERROR_MISSING_SIGNATURE_ALGORITHMS_EXTENSION = (SSL_ERROR_BASE + 157),
SSL_ERROR_MALFORMED_PSK_KEY_EXCHANGE_MODES = (SSL_ERROR_BASE + 158),
SSL_ERROR_MISSING_PSK_KEY_EXCHANGE_MODES = (SSL_ERROR_BASE + 159),
SSL_ERROR_DOWNGRADE_WITH_EARLY_DATA = (SSL_ERROR_BASE + 160),
SSL_ERROR_END_OF_LIST /* let the c compiler determine the value of this. */
} SSLErrorCodes;
#endif /* NO_SECURITY_ERROR_ENUM */

View File

@ -370,6 +370,10 @@ struct sslGatherStr {
/* the start of the buffered DTLS record in dtlsPacket */
unsigned int dtlsPacketOffset;
/* tracks whether we've seen a v3-type record before and must reject
* any further v2-type records. */
PRBool rejectV2Records;
};
/* sslGather.state */

View File

@ -132,7 +132,7 @@ const SSL3ProtocolVersion kDtlsRecordVersion = SSL_LIBRARY_VERSION_TLS_1_1;
PR_STATIC_ASSERT(SSL_LIBRARY_VERSION_MAX_SUPPORTED <=
SSL_LIBRARY_VERSION_TLS_1_3);
/* Use this instead of FATAL_ERROR when an alert isn't possible. */
/* Use this instead of FATAL_ERROR when no alert shall be sent. */
#define LOG_ERROR(ss, prError) \
do { \
SSL_TRC(3, ("%d: TLS13[%d]: fatal error %d in %s (%s:%d)", \

View File

@ -256,11 +256,10 @@ tls13_ClientHandleKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, PR
PORT_Assert(PR_CLIST_IS_EMPTY(&xtnData->remoteKeyShares));
PORT_Assert(!ss->sec.isServer);
/* The server must not send this extension when negotiating < TLS 1.3. */
if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
/* This can't happen because the extension processing
* code filters out TLS 1.3 extensions when not in
* TLS 1.3 mode. */
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
PORT_SetError(SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION);
return SECFailure;
}
@ -691,9 +690,10 @@ tls13_ClientHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData
SSL_TRC(3, ("%d: SSL3[%d]: handle pre_shared_key extension",
SSL_GETPID(), ss->fd));
/* If we are doing < TLS 1.3, then ignore this. */
/* The server must not send this extension when negotiating < TLS 1.3. */
if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
return SECSuccess;
PORT_SetError(SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION);
return SECFailure;
}
rv = ssl3_ExtConsumeHandshakeNumber(ss, &index, 2, &data->data, &data->len);
@ -816,7 +816,7 @@ tls13_ClientHandleEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData, P
SSL_TRC(3, ("%d: TLS13[%d]: handle early_data extension",
SSL_GETPID(), ss->fd));
/* If we are doing < TLS 1.3, then ignore this. */
/* The server must not send this extension when negotiating < TLS 1.3. */
if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
PORT_SetError(SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION);
return SECFailure;
@ -843,7 +843,7 @@ tls13_ClientHandleTicketEarlyDataInfoXtn(const sslSocket *ss, TLSExtensionData *
SSL_TRC(3, ("%d: TLS13[%d]: handle early_data_info extension",
SSL_GETPID(), ss->fd));
/* If we are doing < TLS 1.3, then ignore this. */
/* The server must not send this extension when negotiating < TLS 1.3. */
if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
PORT_SetError(SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION);
return SECFailure;
@ -1093,6 +1093,13 @@ tls13_SendShortHeaderXtn(const sslSocket *ss,
return 0;
}
/* Don't send this if TLS 1.3 isn't at least possible. */
if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_3) {
/* This should only happen on the client. */
PORT_Assert(!ss->sec.isServer);
return 0;
}
SSL_TRC(3, ("%d: TLS13[%d]: send short_header extension",
SSL_GETPID(), ss->fd));
@ -1124,10 +1131,10 @@ tls13_HandleShortHeaderXtn(
const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
SECItem *data)
{
SSL_TRC(3, ("%d: TLS13[%d]: handle early_data extension",
SSL_TRC(3, ("%d: TLS13[%d]: handle short_header extension",
SSL_GETPID(), ss->fd));
/* If we are doing < TLS 1.3, then ignore this. */
/* The client might have asked for this, but we didn't negotiate TLS 1.3. */
if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
return SECSuccess;
}

View File

@ -290,3 +290,9 @@ PORT_DestroyCheapArena;
;+ local:
;+ *;
;+};
;+NSSUTIL_3.25 { # NSS Utilities 3.25 release
;+ global:
SEC_ASN1DecoderSetMaximumElementSize;
;+ local:
;+ *;
;+};

View File

@ -54,6 +54,18 @@ extern void SEC_ASN1DecoderSetNotifyProc(SEC_ASN1DecoderContext *cx,
extern void SEC_ASN1DecoderClearNotifyProc(SEC_ASN1DecoderContext *cx);
/* Sets the maximum size that should be allocated for a single ASN.1
* element. Set to 0 to indicate there is no limit.
*
* Note: This does not set the maximum size overall that may be allocated
* while parsing, nor does it guarantee that the decoder won't allocate
* more than |max_size| while parsing an individual element; rather, it
* merely guarantees that any individual allocation for returned data
* should not exceed |max_size|.
*/
extern void SEC_ASN1DecoderSetMaximumElementSize(SEC_ASN1DecoderContext *cx,
unsigned long max_size);
extern SECStatus SEC_ASN1Decode(PLArenaPool *pool, void *dest,
const SEC_ASN1Template *t,
const char *buf, long len);

View File

@ -292,6 +292,17 @@ struct sec_DecoderContext_struct {
sec_asn1d_state *current;
sec_asn1d_parse_status status;
/* The maximum size the caller is willing to allow a single element
* to be before returning an error.
*
* In the case of an indefinite length element, this is the sum total
* of all child elements.
*
* In the case of a definite length element, this represents the maximum
* size of the top-level element.
*/
unsigned long max_element_size;
SEC_ASN1NotifyProc notify_proc; /* call before/after handling field */
void *notify_arg; /* argument to notify_proc */
PRBool during_notify; /* true during call to notify_proc */
@ -1288,6 +1299,13 @@ sec_asn1d_prepare_for_contents(sec_asn1d_state *state)
alloc_len += subitem->len;
}
if (state->top->max_element_size > 0 &&
alloc_len > state->top->max_element_size) {
PORT_SetError(SEC_ERROR_OUTPUT_LEN);
state->top->status = decodeError;
return;
}
item->data = (unsigned char *)sec_asn1d_zalloc(poolp, alloc_len);
if (item->data == NULL) {
state->top->status = decodeError;
@ -1396,6 +1414,13 @@ sec_asn1d_prepare_for_contents(sec_asn1d_state *state)
if (state->dest != NULL) {
item = (SECItem *)(state->dest);
item->len = 0;
if (state->top->max_element_size > 0 &&
state->contents_length > state->top->max_element_size) {
PORT_SetError(SEC_ERROR_OUTPUT_LEN);
state->top->status = decodeError;
return;
}
if (state->top->filter_only) {
item->data = NULL;
} else {
@ -2223,6 +2248,13 @@ sec_asn1d_concat_substrings(sec_asn1d_state *state)
alloc_len = item_len;
}
if (state->top->max_element_size > 0 &&
alloc_len > state->top->max_element_size) {
PORT_SetError(SEC_ERROR_OUTPUT_LEN);
state->top->status = decodeError;
return;
}
item = (SECItem *)(state->dest);
PORT_Assert(item != NULL);
PORT_Assert(item->data == NULL);
@ -2726,7 +2758,7 @@ SEC_ASN1DecoderUpdate(SEC_ASN1DecoderContext *cx,
#ifdef DEBUG_ASN1D_STATES
printf("\nPLACE = %s, next byte = 0x%02x, %08x[%d]\n",
(state->place >= 0 && state->place <= notInUse) ? place_names[state->place] : "(undefined)",
(unsigned int)((unsigned char *)buf)[consumed],
len ? (unsigned int)((unsigned char *)buf)[consumed] : 0,
buf, consumed);
dump_states(cx);
#endif /* DEBUG_ASN1D_STATES */
@ -3041,6 +3073,13 @@ SEC_ASN1DecoderClearNotifyProc(SEC_ASN1DecoderContext *cx)
cx->notify_arg = NULL; /* not necessary; just being clean */
}
void
SEC_ASN1DecoderSetMaximumElementSize(SEC_ASN1DecoderContext *cx,
unsigned long max_size)
{
cx->max_element_size = max_size;
}
void
SEC_ASN1DecoderAbort(SEC_ASN1DecoderContext *cx, int error)
{
@ -3061,6 +3100,10 @@ SEC_ASN1Decode(PLArenaPool *poolp, void *dest,
if (dcx == NULL)
return SECFailure;
/* In one-shot mode, there's no possibility of streaming data beyond the
* length of len */
SEC_ASN1DecoderSetMaximumElementSize(dcx, len);
urv = SEC_ASN1DecoderUpdate(dcx, buf, len);
frv = SEC_ASN1DecoderFinish(dcx);

View File

@ -0,0 +1,4 @@
---
Language: Cpp
BasedOnStyle: Google
...

View File

@ -0,0 +1,23 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "argparse.h"
ArgParser::ArgParser(const std::vector<std::string>& arguments) {
for (size_t i = 0; i < arguments.size(); i++) {
std::string arg = arguments.at(i);
if (arg.find("--") == 0) {
// look for an option argument
if (i + 1 < arguments.size() && arguments.at(i + 1).find("--") != 0) {
programArgs_[arg] = arguments.at(i + 1);
i++;
} else {
programArgs_[arg] = "";
}
} else {
// positional argument (e.g. required argument)
positionalArgs_.push_back(arg);
}
}
}

View File

@ -0,0 +1,30 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef argparse_h__
#define argparse_h__
#include <string>
#include <unordered_map>
#include <vector>
class ArgParser {
public:
ArgParser(const std::vector<std::string>& arguments);
bool Has(std::string arg) { return programArgs_.count(arg) > 0; }
std::string Get(std::string arg) { return programArgs_[arg]; }
size_t GetPositionalArgumentCount() { return positionalArgs_.size(); }
std::string GetPositionalArgument(size_t pos) {
return positionalArgs_.at(pos);
}
private:
std::unordered_map<std::string, std::string> programArgs_;
std::vector<std::string> positionalArgs_;
};
#endif // argparse_h__

View File

@ -0,0 +1,57 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef scoped_ptrs_h__
#define scoped_ptrs_h__
#include <memory>
#include "cert.h"
#include "keyhi.h"
#include "pk11pub.h"
struct ScopedDelete {
void operator()(CERTCertificate* cert) { CERT_DestroyCertificate(cert); }
void operator()(CERTCertificateList* list) {
CERT_DestroyCertificateList(list);
}
void operator()(CERTSubjectPublicKeyInfo* spki) {
SECKEY_DestroySubjectPublicKeyInfo(spki);
}
void operator()(PK11SlotInfo* slot) { PK11_FreeSlot(slot); }
void operator()(PK11SymKey* key) { PK11_FreeSymKey(key); }
void operator()(SECAlgorithmID* id) { SECOID_DestroyAlgorithmID(id, true); }
void operator()(SECItem* item) { SECITEM_FreeItem(item, true); }
void operator()(SECKEYPublicKey* key) { SECKEY_DestroyPublicKey(key); }
void operator()(SECKEYPrivateKey* key) { SECKEY_DestroyPrivateKey(key); }
void operator()(CERTCertList* list) { CERT_DestroyCertList(list); }
};
template <class T>
struct ScopedMaybeDelete {
void operator()(T* ptr) {
if (ptr) {
ScopedDelete del;
del(ptr);
}
}
};
#define SCOPED(x) typedef std::unique_ptr<x, ScopedMaybeDelete<x> > Scoped##x
SCOPED(CERTCertificate);
SCOPED(CERTCertificateList);
SCOPED(CERTSubjectPublicKeyInfo);
SCOPED(PK11SlotInfo);
SCOPED(PK11SymKey);
SCOPED(SECAlgorithmID);
SCOPED(SECItem);
SCOPED(SECKEYPublicKey);
SCOPED(SECKEYPrivateKey);
SCOPED(CERTCertList);
#undef SCOPED
#endif

View File

@ -0,0 +1,138 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "dbtool.h"
#include "argparse.h"
#include "scoped_ptrs.h"
#include <iomanip>
#include <iostream>
#include <memory>
#include <sstream>
#include <cert.h>
#include <certdb.h>
#include <nss.h>
#include <prio.h>
static std::string PrintFlags(unsigned int flags) {
std::stringstream ss;
if ((flags & CERTDB_VALID_CA) && !(flags & CERTDB_TRUSTED_CA) &&
!(flags & CERTDB_TRUSTED_CLIENT_CA)) {
ss << "c";
}
if ((flags & CERTDB_TERMINAL_RECORD) && !(flags & CERTDB_TRUSTED)) {
ss << "p";
}
if (flags & CERTDB_TRUSTED_CA) {
ss << "C";
}
if (flags & CERTDB_TRUSTED_CLIENT_CA) {
ss << "T";
}
if (flags & CERTDB_TRUSTED) {
ss << "P";
}
if (flags & CERTDB_USER) {
ss << "u";
}
if (flags & CERTDB_SEND_WARN) {
ss << "w";
}
if (flags & CERTDB_INVISIBLE_CA) {
ss << "I";
}
if (flags & CERTDB_GOVT_APPROVED_CA) {
ss << "G";
}
return ss.str();
}
void DBTool::Usage() {
std::cerr << "Usage: nss db [--path <directory>] --list-certs" << std::endl;
}
bool DBTool::Run(const std::vector<std::string> &arguments) {
ArgParser parser(arguments);
std::string initDir(".");
if (parser.Has("--path")) {
initDir = parser.Get("--path");
if (PR_Access(initDir.c_str(), PR_ACCESS_READ_OK) != PR_SUCCESS) {
std::cerr << "Directory '" << initDir
<< "' does not exists or you don't have permissions!"
<< std::endl;
return false;
}
}
if (!parser.Has("--list-certs")) {
return false;
}
std::cout << "Using database directory: " << initDir << std::endl
<< std::endl;
// init NSS
const char *certPrefix = ""; // certutil -P option --- can leave this empty
SECStatus rv =
NSS_Initialize(initDir.c_str(), certPrefix, certPrefix, "secmod.db", 0);
if (rv != SECSuccess) {
std::cerr << "NSS init failed!" << std::endl;
return false;
}
ListCertificates();
// shutdown nss
if (NSS_Shutdown() != SECSuccess) {
std::cerr << "NSS Shutdown failed!" << std::endl;
return false;
}
return true;
}
void DBTool::ListCertificates() {
ScopedCERTCertList list(PK11_ListCerts(PK11CertListAll, nullptr));
CERTCertListNode *node;
std::cout << std::setw(60) << std::left << "Certificate Nickname"
<< " "
<< "Trust Attributes" << std::endl;
std::cout << std::setw(60) << std::left << ""
<< " "
<< "SSL,S/MIME,JAR/XPI" << std::endl
<< std::endl;
for (node = CERT_LIST_HEAD(list); !CERT_LIST_END(node, list);
node = CERT_LIST_NEXT(node)) {
CERTCertificate *cert = node->cert;
std::string name("(unknown)");
char *appData = static_cast<char *>(node->appData);
if (appData && strlen(appData) > 0) {
name = appData;
} else if (cert->nickname && strlen(cert->nickname) > 0) {
name = cert->nickname;
} else if (cert->emailAddr && strlen(cert->emailAddr) > 0) {
name = cert->emailAddr;
}
CERTCertTrust trust;
std::string trusts;
if (CERT_GetCertTrust(cert, &trust) == SECSuccess) {
std::stringstream ss;
ss << PrintFlags(trust.sslFlags);
ss << ",";
ss << PrintFlags(trust.emailFlags);
ss << ",";
ss << PrintFlags(trust.objectSigningFlags);
trusts = ss.str();
} else {
trusts = ",,";
}
std::cout << std::setw(60) << std::left << name << " " << trusts
<< std::endl;
}
}

View File

@ -0,0 +1,21 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef dbtool_h__
#define dbtool_h__
#include <string>
#include <vector>
class DBTool {
public:
bool Run(const std::vector<std::string>& arguments);
void Usage();
private:
void ListCertificates();
};
#endif // dbtool_h__

View File

@ -0,0 +1,43 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <iostream>
#include <string>
#include <vector>
#include <prinit.h>
#include "argparse.h"
#include "db/dbtool.h"
static void Usage() {
std::cerr << "Usage: nss <command> <subcommand> [options]" << std::endl;
std::cerr << " nss db [--path <directory>] --list-certs" << std::endl;
}
int main(int argc, char **argv) {
if (argc < 2) {
Usage();
return 1;
}
if (std::string(argv[1]) != "db") {
Usage();
return 1;
}
int exit_code = 0;
PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
std::vector<std::string> arguments(argv + 2, argv + argc);
DBTool tool;
if (!tool.Run(arguments)) {
tool.Usage();
exit_code = 1;
}
PR_Cleanup();
return exit_code;
}

View File

@ -0,0 +1,27 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
{
'includes' : [
'../coreconf/config.gypi',
'../cmd/platlibs.gypi',
],
'targets' : [
{
'target_name' : 'nss',
'type' : 'executable',
'sources' : [
'nss_tool.cc',
'common/argparse.cc',
'db/dbtool.cc',
],
'include_dirs': [
'common',
],
'dependencies' : [
'<(DEPTH)/exports.gyp:dbm_exports',
'<(DEPTH)/exports.gyp:nss_exports'
],
}
],
}

View File

@ -120,6 +120,7 @@
'cmd/smimetools/smimetools.gyp:cmsutil',
'cmd/ssltap/ssltap.gyp:ssltap',
'cmd/symkeyutil/symkeyutil.gyp:symkeyutil',
'nss-tool/nss_tool.gyp:nss',
],
}],
],
@ -177,7 +178,6 @@
'cmd/vfychain/vfychain.gyp:vfychain',
'cmd/vfyserv/vfyserv.gyp:vfyserv',
'gtests/google_test/google_test.gyp:gtest1',
'gtests/common/common.gyp:gtests',
'gtests/der_gtest/der_gtest.gyp:der_gtest',
'gtests/pk11_gtest/pk11_gtest.gyp:pk11_gtest',
'gtests/ssl_gtest/ssl_gtest.gyp:ssl_gtest',
@ -241,7 +241,7 @@
},
],
}],
[ 'fuzz==1', {
[ 'fuzz_tls==1', {
'targets': [
{
'target_name': 'fuzz_warning',
@ -256,12 +256,16 @@
}
],
},
],
}],
[ 'fuzz==1', {
'targets': [
{
'target_name': 'fuzz',
'type': 'none',
'dependencies': [
'fuzz/fuzz.gyp:nssfuzz',
]
],
},
],
}],

View File

@ -2,8 +2,8 @@
Network Security Services (NSS) is a set of libraries designed to support
cross-platform development of security-enabled client and server
applications. NSS supports SSL v3-TLS 1.2 (experimental TLS 1.3), PKCS #5, PKCS
#7, PKCS #11, PKCS #12, S/MIME, X.509 v3 certificates, and other security
applications. NSS supports SSL v3-TLS 1.2 (experimental TLS 1.3), PKCS #5, PKCS#7,
PKCS #11, PKCS #12, S/MIME, X.509 v3 certificates, and other security
standards.
## Getting started
@ -34,15 +34,16 @@ After changing into the NSS directory a typical build is done as follows
./build.sh
Once the build is done the build output is found in the directory
`../dist/*.OBJ`, where `*` will be a name dynamically derived from your system's
architecture. Exported header files can be found in the `include` directory,
library files in directory `lib`, and tools in directory `bin`. In order to run
the tools, set your system environment to use the libraries of your build from
the "lib" directory, e.g., using the `LD_LIBRARY_PATH` or `DYLD_LIBRARY_PATH`.
`../dist/Debug` for debug builds and `../dist/Release` for opt builds.
Exported header files can be found in the `include` directory, library files in
directory `lib`, and tools in directory `bin`. In order to run the tools, set
your system environment to use the libraries of your build from the "lib"
directory, e.g., using the `LD_LIBRARY_PATH` or `DYLD_LIBRARY_PATH`.
Usage: build.sh [-hcgv] [-j <n>] [--test] [--fuzz] [--scan-build[=output]]
[-m32] [--opt|-o] [--asan] [--ubsan] [--sancov[=edge|bb|func]]
[--pprof] [--msan]
Usage: build.sh [-hcv] [-j <n>] [--nspr] [--gyp|-g] [--opt|-o] [-m32]
[--test] [--fuzz] [--pprof] [--scan-build[=output]]
[--asan] [--ubsan] [--msan] [--sancov[=edge|bb|func|...]]
[--ct-verif] [--disable-tests]
This script builds NSS with gyp and ninja.
@ -51,24 +52,27 @@ the "lib" directory, e.g., using the `LD_LIBRARY_PATH` or `DYLD_LIBRARY_PATH`.
NSS build tool options:
-h display this help and exit
-c clean before build
-g force a rebuild of gyp (and NSPR, because why not)
-j <n> run at most <n> concurrent jobs
-v verbose build
-m32 do a 32-bit build on a 64-bit system
--test ignore map files and export everything we have
--fuzz enable fuzzing mode. this always enables test builds
--scan-build run the build with scan-build (scan-build has to be in the path)
--scan-build=/out/path sets the output path for scan-build
--opt|-o do an opt build
--asan do an asan build
--ubsan do an ubsan build
--msan do an msan build
--sancov do sanitize coverage builds
--sancov=func sets coverage to function level for example
--pprof build with gperftool support
-h display this help and exit
-c clean before build
-v verbose build
-j <n> run at most <n> concurrent jobs
--nspr force a rebuild of NSPR
--gyp|-g force a rerun of gyp
--opt|-o do an opt build
-m32 do a 32-bit build on a 64-bit system
--test ignore map files and export everything we have
--fuzz enable fuzzing mode. this always enables test builds
--pprof build with gperftool support
--ct-verif build with valgrind for ct-verif
--scan-build run the build with scan-build (scan-build has to be in the path)
--scan-build=/out/path sets the output path for scan-build
--asan do an asan build
--ubsan do an ubsan build
--ubsan=bool,shift,... sets specific UB sanitizers
--msan do an msan build
--sancov do sanitize coverage builds
--sancov=func sets coverage to function level for example
--disable-tests don't build tests and corresponding cmdline utils
## Building NSS (legacy build system)

View File

@ -39,6 +39,8 @@
# gtests.sh - Gtest based unit tests for everything else
# bogo.sh - Bogo interop tests (disabled by default)
# https://boringssl.googlesource.com/boringssl/+/master/ssl/test/PORTING.md
# interop.sh - Interoperability tests (disabled by default)
# https://github.com/ekr/tls_interop
#
# NSS testing is now devided to 4 cycles:
# ---------------------------------------

View File

@ -39,9 +39,6 @@ bogo_cleanup()
. common/cleanup.sh
}
# Need to add go to the PATH.
export PATH=$PATH:/usr/lib/go-1.6/bin
cd "$(dirname "$0")"
SOURCE_DIR="$PWD"/../..
bogo_init

View File

@ -0,0 +1,68 @@
#!/bin/bash
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
########################################################################
#
# tests/interop/interop.sh
#
# Script to drive our cross-stack interop tests
#
########################################################################
interop_init()
{
SCRIPTNAME="interop.sh"
if [ -z "${INIT_SOURCED}" -o "${INIT_SOURCED}" != "TRUE" ] ; then
cd ../common
. ./init.sh
fi
mkdir -p "${HOSTDIR}/interop"
cd "${HOSTDIR}/interop"
INTEROP=${INTEROP:=tls_interop}
if [ ! -d "$INTEROP" ]; then
git clone -q https://github.com/mozilla/tls-interop "$INTEROP"
fi
# We use the BoringSSL keyfiles
BORING=${BORING:=boringssl}
if [ ! -d "$BORING" ]; then
git clone -q https://boringssl.googlesource.com/boringssl "$BORING"
git -C "$BORING" checkout -q ea80f9d5df4c302de391e999395e1c87f9c786b3
fi
SCRIPTNAME="interop.sh"
html_head "interop test"
}
interop_cleanup()
{
html "</TABLE><BR>"
cd ${QADIR}
. common/cleanup.sh
}
# Function so we can easily add other stacks
interop_run()
{
test_name=$1
client=$2
server=$3
(cd "$INTEROP";
cargo run -- --client ${client} --server ${server} --rootdir ../${BORING}/ssl/test/runner/ --test-cases cases.json) 2>interop-${test_name}.errors | tee interop-${test_name}.log
html_msg "${PIPESTATUS[0]}" 0 "Interop" "Run successfully"
grep -i 'FAILED\|Assertion failure' interop-${test_name}.errors
html_msg $? 1 "Interop" "No failures"
}
cd "$(dirname "$0")"
SOURCE_DIR="$PWD"/../..
interop_init
NSS_SHIM="${BINDIR}"/nss_bogo_shim
BORING_SHIM="../${BORING}"/build/ssl/test/bssl_shim
interop_run "nss_nss" ${NSS_SHIM} ${NSS_SHIM}
interop_cleanup