Architecture specific change in rpms/golang-github-influxdata-flux.git
by githook-noreply@fedoraproject.org
The package rpms/golang-github-influxdata-flux.git has added or updated architecture specific content in its
spec file (ExclusiveArch/ExcludeArch or %ifarch/%ifnarch) in commit(s):
https://src.fedoraproject.org/cgit/rpms/golang-github-influxdata-flux.git....
Change:
-%ifnarch s390x
Thanks.
Full change:
============
commit 31fd5ff85a0e43f0d08ca8ee1386d6c53d5c7595
Author: Robert-André Mauchin <zebob.m(a)gmail.com>
Date: Tue Sep 8 21:00:46 2020 +0200
Update to 0.83.1
Signed-off-by: Robert-André Mauchin <zebob.m(a)gmail.com>
diff --git a/.gitignore b/.gitignore
index 5163f6b..9e8e4df 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,7 @@
/flux-0.37.2.tar.gz
/flux-0.59.5.tar.gz
/flux-0.65.0.tar.gz
+/flux-0.71.0.tar.gz
+/flux-0.74.0.tar.gz
+/flux-0.79.0.tar.gz
+/flux-0.83.1.tar.gz
diff --git a/golang-github-influxdata-flux.spec b/golang-github-influxdata-flux.spec
index 7952dc6..e7917ed 100644
--- a/golang-github-influxdata-flux.spec
+++ b/golang-github-influxdata-flux.spec
@@ -1,11 +1,10 @@
# Generated by go2rpm
-%ifnarch s390x
-%bcond_without check
-%endif
+# Need main flux library
+%bcond_with check
# https://github.com/influxdata/flux
%global goipath github.com/influxdata/flux
-Version: 0.65.0
+Version: 0.83.1
%gometa
@@ -20,7 +19,7 @@ independently of those.}
%global gosupfiles "${flux[@]}" stdlib/testing/testdata/* stdlib/pandas_tests/testdata/* stdlib/strings/testdata/*
Name: %{goname}
-Release: 3%{?dist}
+Release: 1%{?dist}
Summary: Lightweight scripting language for querying databases
License: MIT
@@ -28,18 +27,25 @@ URL: %{gourl}
Source0: %{gosource}
BuildRequires: golang(cloud.google.com/go/bigtable)
+BuildRequires: golang(cloud.google.com/go/civil)
BuildRequires: golang(github.com/andreyvit/diff)
BuildRequires: golang(github.com/apache/arrow/go/arrow)
BuildRequires: golang(github.com/apache/arrow/go/arrow/array)
BuildRequires: golang(github.com/apache/arrow/go/arrow/bitutil)
BuildRequires: golang(github.com/apache/arrow/go/arrow/math)
BuildRequires: golang(github.com/apache/arrow/go/arrow/memory)
+BuildRequires: golang(github.com/Azure/go-autorest/autorest/adal)
+BuildRequires: golang(github.com/Azure/go-autorest/autorest/azure)
+BuildRequires: golang(github.com/Azure/go-autorest/autorest/azure/auth)
# BuildRequires: golang(github.com/benbjohnson/tmpl)
+BuildRequires: golang(github.com/bonitoo-io/go-sql-bigquery)
BuildRequires: golang(github.com/c-bata/go-prompt)
BuildRequires: golang(github.com/cespare/xxhash)
BuildRequires: golang(github.com/dave/jennifer/jen)
+BuildRequires: golang(github.com/denisenkom/go-mssqldb)
BuildRequires: golang(github.com/eclipse/paho.mqtt.golang)
BuildRequires: golang(github.com/go-sql-driver/mysql)
+BuildRequires: golang(github.com/gofrs/uuid)
BuildRequires: golang(github.com/golang/geo/r1)
BuildRequires: golang(github.com/golang/geo/s1)
BuildRequires: golang(github.com/golang/geo/s2)
@@ -49,8 +55,8 @@ BuildRequires: golang(github.com/google/go-cmp/cmp/cmpopts)
# BuildRequires: golang(github.com/goreleaser/goreleaser)
# BuildRequires: golang(github.com/influxdata/changelog)
BuildRequires: golang(github.com/influxdata/line-protocol)
-BuildRequires: golang(github.com/influxdata/promql)
-BuildRequires: golang(github.com/influxdata/promql/pkg/labels)
+BuildRequires: golang(github.com/influxdata/promql/v2)
+BuildRequires: golang(github.com/influxdata/promql/v2/pkg/labels)
BuildRequires: golang(github.com/influxdata/tdigest)
BuildRequires: golang(github.com/lib/pq)
BuildRequires: golang(github.com/mattn/go-sqlite3)
@@ -61,15 +67,19 @@ BuildRequires: golang(github.com/pkg/errors)
BuildRequires: golang(github.com/prometheus/client_model/go)
BuildRequires: golang(github.com/prometheus/common/expfmt)
BuildRequires: golang(github.com/prometheus/common/model)
-BuildRequires: golang(github.com/satori/go.uuid)
BuildRequires: golang(github.com/segmentio/kafka-go)
+BuildRequires: golang(github.com/snowflakedb/gosnowflake)
BuildRequires: golang(github.com/spf13/cobra)
-BuildRequires: golang(github.com/spf13/pflag)
+BuildRequires: golang(github.com/uber/athenadriver/go)
BuildRequires: golang(go.uber.org/zap)
BuildRequires: golang(go.uber.org/zap/zapcore)
BuildRequires: golang(go.uber.org/zap/zaptest)
BuildRequires: golang(golang.org/x/net/context)
+BuildRequires: golang(golang.org/x/tools/go/callgraph)
+BuildRequires: golang(golang.org/x/tools/go/callgraph/rta)
BuildRequires: golang(golang.org/x/tools/go/packages)
+BuildRequires: golang(golang.org/x/tools/go/ssa)
+BuildRequires: golang(golang.org/x/tools/go/ssa/ssautil)
BuildRequires: golang(gonum.org/v1/gonum/floats)
BuildRequires: golang(google.golang.org/api/option)
# BuildRequires: golang(honnef.co/go/tools/cmd/staticcheck)
@@ -88,17 +98,9 @@ BuildRequires: golang(github.com/DATA-DOG/go-sqlmock)
%goprep
rm -rf internal/tools
mapfile -t flux <<< $(find . -iname "*.flux" -type f)
-sed -i "s|github.com/influxdata/promql/v2|github.com/influxdata/promql|" $(find . -iname "*.go")
-
-%build
-for cmd in cmd/* ; do
- %gobuild -o %{gobuilddir}/bin/$(basename $cmd) %{goipath}/$cmd
-done
%install
%gopkginstall
-install -m 0755 -vd %{buildroot}%{_bindir}
-install -m 0755 -vp %{gobuilddir}/bin/* %{buildroot}%{_bindir}/
%if %{with check}
%check
@@ -106,14 +108,12 @@ install -m 0755 -vp %{gobuilddir}/bin/* %{buildroot}%{_bindir}/
-d execute
%endif
-%files
-%license %{golicenses}
-%doc %{godocs}
-%{_bindir}/*
-
%gopkgfiles
%changelog
+* Tue Sep 08 18:43:39 CEST 2020 Robert-André Mauchin <zebob.m(a)gmail.com> - 0.83.1-1
+- Update to 0.83.1
+
* Sat Aug 01 2020 Fedora Release Engineering <releng(a)fedoraproject.org> - 0.65.0-3
- Second attempt - Rebuilt for
https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild
diff --git a/sources b/sources
index 376b49e..072d852 100644
--- a/sources
+++ b/sources
@@ -1 +1 @@
-SHA512 (flux-0.65.0.tar.gz) = 2354c53fd724a62d21e54a127d7fabac9c8775c97c1a3f1fffb2802bed51f4f5ab869929945d2698a1aab8e4c5c05b99d3beb392cdbf163791866349a9cb81a1
+SHA512 (flux-0.83.1.tar.gz) = 44d1de266293bcba15cfd81e43a4b60edb7f05ed35f02be102c5ce55808053672d4268a7f3b016d87a42bde5a53c90d4e1fb7bfb87927178de74dd8bd681bcb9
3 years, 8 months
Architecture specific change in rpms/nodejs.git
by githook-noreply@fedoraproject.org
The package rpms/nodejs.git has added or updated architecture specific content in its
spec file (ExclusiveArch/ExcludeArch or %ifarch/%ifnarch) in commit(s):
https://src.fedoraproject.org/cgit/rpms/nodejs.git/commit/?id=0ea33eec603....
Change:
+%ifarch armv7hl
Thanks.
Full change:
============
commit 71cddf00f433f16a0decd8c15557ed9e66a12597
Merge: 17ff18b f2dbb7e
Author: Stephen Gallagher <sgallagh(a)redhat.com>
Date: Tue Sep 8 14:51:45 2020 -0400
Merge branch 'master' into f33
commit f2dbb7e6ed0103c4140fdec399fde5399468cce7
Author: Stephen Gallagher <sgallagh(a)redhat.com>
Date: Tue Sep 8 14:13:55 2020 -0400
Update to 14.10.0
Signed-off-by: Stephen Gallagher <sgallagh(a)redhat.com>
diff --git a/nodejs.spec b/nodejs.spec
index 88beabe..2b8bb6a 100644
--- a/nodejs.spec
+++ b/nodejs.spec
@@ -7,7 +7,7 @@
# This is used by both the nodejs package and the npm subpackage thar
# has a separate version - the name is special so that rpmdev-bumpspec
# will bump this rather than adding .1 to the end.
-%global baserelease 2
+%global baserelease 1
%{?!_pkgdocdir:%global _pkgdocdir %{_docdir}/%{name}-%{version}}
@@ -18,7 +18,7 @@
# than a Fedora release lifecycle.
%global nodejs_epoch 1
%global nodejs_major 14
-%global nodejs_minor 7
+%global nodejs_minor 10
%global nodejs_patch 0
%global nodejs_abi %{nodejs_major}.%{nodejs_minor}
# nodejs_soversion - from NODE_MODULE_VERSION in src/node_version.h
@@ -56,8 +56,8 @@
# libuv - from deps/uv/include/uv/version.h
%global libuv_major 1
-%global libuv_minor 38
-%global libuv_patch 1
+%global libuv_minor 39
+%global libuv_patch 0
%global libuv_version %{libuv_major}.%{libuv_minor}.%{libuv_patch}
# nghttp2 - from deps/nghttp2/lib/includes/nghttp2/nghttp2ver.h
@@ -91,13 +91,13 @@
%global npm_epoch 1
%global npm_major 6
%global npm_minor 14
-%global npm_patch 7
+%global npm_patch 8
%global npm_version %{npm_major}.%{npm_minor}.%{npm_patch}
# uvwasi - from deps/uvwasi/include/uvwasi.h
%global uvwasi_major 0
%global uvwasi_minor 0
-%global uvwasi_patch 9
+%global uvwasi_patch 10
%global uvwasi_version %{uvwasi_major}.%{uvwasi_minor}.%{uvwasi_patch}
# histogram_c - assumed from timestamps
@@ -473,8 +473,9 @@ ln -s libnode.so.%{nodejs_soversion} %{buildroot}%{_libdir}/libnode.so
# Install v8 compatibility symlinks
for header in %{buildroot}%{_includedir}/node/libplatform %{buildroot}%{_includedir}/node/v8*.h; do
header=$(basename ${header})
- ln -s %{_includedir}/node/${header} %{buildroot}%{_includedir}/${header}
+ ln -s ./node/${header} %{buildroot}%{_includedir}/${header}
done
+ln -s ./node/cppgc %{buildroot}%{_includedir}/cppgc
for soname in libv8 libv8_libbase libv8_libplatform; do
ln -s libnode.so.%{nodejs_soversion} %{buildroot}%{_libdir}/${soname}.so
ln -s libnode.so.%{nodejs_soversion} %{buildroot}%{_libdir}/${soname}.so.%{v8_major}
@@ -688,6 +689,9 @@ end
%changelog
+* Tue Sep 08 2020 Stephen Gallagher <sgallagh(a)redhat.com> - 1:14.10.0-1
+- Update to 14.10.0
+
* Fri Aug 21 2020 Jeff Law <law(a)redhat.com> - 1:14.7.0-2
- Narrow LTO opt-out to just armv7hl
diff --git a/sources b/sources
index b64ce65..927ee67 100644
--- a/sources
+++ b/sources
@@ -1,2 +1,2 @@
-SHA512 (node-v14.7.0-stripped.tar.gz) = b348851102b9cf204478b2b0d3eafc82287f6f32beee182fc1f77cad3636a1a529a31d4404ba310163d0f6c05209ba32acc9f4543204ec5bc25201ac2da662cf
+SHA512 (node-v14.10.0-stripped.tar.gz) = d0e5235112f6a3a8d76a6c88c1c52ac266e726d59257157435d0fcc81452f873d446490006a38b226a8dbb94e1f8e999eda61ea3064a5d993ecfeb31122bf649
SHA512 (icu4c-67_1-src.tgz) = 4779f1ce1ca7976f6fad6768853ea8c540da54d11509e3b6cfd864a04b5f2db1c3d4b546387f91ad02fb90804525bc37d2543173f0d705d6ca11dc6f2b7640a8
commit 0ea33eec603687e056b3e576a0215d400ff300e0
Author: Jeff Law <law(a)redhat.com>
Date: Fri Aug 21 09:04:40 2020 -0600
Narrow LTO opt-opt to just armv7hl
diff --git a/nodejs.spec b/nodejs.spec
index 26dc400..88beabe 100644
--- a/nodejs.spec
+++ b/nodejs.spec
@@ -7,7 +7,7 @@
# This is used by both the nodejs package and the npm subpackage thar
# has a separate version - the name is special so that rpmdev-bumpspec
# will bump this rather than adding .1 to the end.
-%global baserelease 1
+%global baserelease 2
%{?!_pkgdocdir:%global _pkgdocdir %{_docdir}/%{name}-%{version}}
@@ -364,9 +364,11 @@ find . -type f -exec sed -i "s~python -c~python3 -c~" {} \;
%endif
%build
-# This package has static probes which do not work with LTO
-# Disable LTO
+# When compiled on armv7hl this package generates an out of range
+# reference to the literal pool. This is most likely a GCC issue.
+%ifarch armv7hl
%define _lto_cflags %{nil}
+%endif
%ifarch s390 s390x %{arm} %ix86
# Decrease debuginfo verbosity to reduce memory consumption during final
@@ -686,6 +688,9 @@ end
%changelog
+* Fri Aug 21 2020 Jeff Law <law(a)redhat.com> - 1:14.7.0-2
+- Narrow LTO opt-out to just armv7hl
+
* Fri Jul 31 2020 Stephen Gallagher <sgallagh(a)redhat.com> - 1:14.7.0-1
- Update to 14.7.0
3 years, 8 months
Architecture specific change in rpms/atlas.git
by githook-noreply@fedoraproject.org
The package rpms/atlas.git has added or updated architecture specific content in its
spec file (ExclusiveArch/ExcludeArch or %ifarch/%ifnarch) in commit(s):
https://src.fedoraproject.org/cgit/rpms/atlas.git/commit/?id=9a83c6c2acd0....
Change:
+%ifarch s390 s390x
Thanks.
Full change:
============
commit 9a83c6c2acd00d97a73b00e78a6a321dd3e626e9
Author: Jakub Martisko <jamartis(a)redhat.com>
Date: Fri Aug 28 17:23:01 2020 +0200
sync with rhel 8.3
- add the z14 and z15 subpackages. Unlike in RHEL, the base s390 package is still build
for z12.
- add some covscan related fixes from rhel
- minor cleanup of the spec file/unused patches
diff --git a/.gitignore b/.gitignore
index 6661901..0700b1c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,3 +10,6 @@ K7323DNow.tgz
/lapack-3.5.0.tgz
/atlas3.10.2.tar.bz2
/POWER864LEVSXp4.tar.bz2
+/IBMz1364VXZ.tar.bz2
+/IBMz1464VXZ2.tar.bz2
+/IBMz1564VXZ2.tar.bz2
diff --git a/atlas-aarch64port.patch b/atlas-aarch64port.patch
deleted file mode 100644
index ad06226..0000000
--- a/atlas-aarch64port.patch
+++ /dev/null
@@ -1,219 +0,0 @@
-Author: Mark Salter <msalter(a)redhat.com>
-
-Index: ATLAS/CONFIG/include/atlconf.h
-===================================================================
---- ATLAS.orig/CONFIG/include/atlconf.h
-+++ ATLAS/CONFIG/include/atlconf.h
-@@ -16,9 +16,9 @@ enum OSTYPE {OSOther=0, OSLinux, OSSunOS
- ((OS_) == OSWin64) )
-
- enum ARCHFAM {AFOther=0, AFPPC, AFSPARC, AFALPHA, AFX86, AFIA64, AFMIPS,
-- AFARM, AFS390};
-+ AFARM, AFS390, AFAARCH64};
-
--#define NMACH 52
-+#define NMACH 53
- static char *machnam[NMACH] =
- {"UNKNOWN", "POWER3", "POWER4", "POWER5", "PPCG4", "PPCG5",
- "POWER6", "POWER7", "POWERe6500", "IBMz9", "IBMz10", "IBMz196",
-@@ -29,7 +29,7 @@ static char *machnam[NMACH] =
- "Efficeon", "K7", "HAMMER", "AMD64K10h", "AMDLLANO", "AMDDOZER","AMDDRIVER",
- "UNKNOWNx86", "IA64Itan", "IA64Itan2",
- "USI", "USII", "USIII", "USIV", "UST1", "UST2", "UnknownUS",
-- "MIPSR1xK", "MIPSICE9", "ARMv7"};
-+ "MIPSR1xK", "MIPSICE9", "ARMv7", "AARCH64"};
- enum MACHTYPE {MACHOther, IbmPwr3, IbmPwr4, IbmPwr5, PPCG4, PPCG5,
- IbmPwr6, IbmPwr7, Pwre6500,
- IbmZ9, IbmZ10, IbmZ196, /* s390(x) in Linux */
-@@ -42,7 +42,8 @@ enum MACHTYPE {MACHOther, IbmPwr3, IbmPw
- SunUSI, SunUSII, SunUSIII, SunUSIV, SunUST1, SunUST2, SunUSX,
- MIPSR1xK, /* includes R10K, R12K, R14K, R16K */
- MIPSICE9, /* SiCortex ICE9 -- like MIPS5K */
-- ARMv7 /* includes Cortex A8, A9 */
-+ ARMv7, /* includes Cortex A8, A9 */
-+ AARCH64
- };
- #define MachIsX86(mach_) \
- ( (mach_) >= x86x87 && (mach_) <= x86X )
-@@ -63,6 +64,8 @@ enum MACHTYPE {MACHOther, IbmPwr3, IbmPw
- ( (mach_) == ARMv7 )
- #define MachIsS390(mach_) \
- ( (mach_) >= IbmZ9 && (mach_) <= IbmZ196 )
-+#define MachIsAARCH64(mach_) \
-+ ( (mach_) == AARCH64 )
-
-
- static char *f2c_namestr[5] = {"UNKNOWN","Add_", "Add__", "NoChange", "UpCase"};
-@@ -84,13 +87,13 @@ enum ISAEXT
- {ISA_None=0, ISA_VSX, ISA_AV, ISA_AVXMAC, ISA_AVXFMA4, ISA_AVX,
- ISA_SSE3, ISA_SSE2, ISA_SSE1, ISA_3DNow, ISA_NEON};
-
--#define NASMD 9
-+#define NASMD 10
- enum ASMDIA
- {ASM_None=0, gas_x86_32, gas_x86_64, gas_sparc, gas_ppc, gas_parisc,
-- gas_mips, gas_arm, gas_s390};
-+ gas_mips, gas_arm, gas_s390, gas_aarch64};
- static char *ASMNAM[NASMD] =
- {"", "GAS_x8632", "GAS_x8664", "GAS_SPARC", "GAS_PPC", "GAS_PARISC",
-- "GAS_MIPS", "GAS_ARM", "GAS_S390"};
-+ "GAS_MIPS", "GAS_ARM", "GAS_S390", "GAS_AARCH64"};
-
- /*
- * Used for archinfo probes (can pack in bitfield)
-Index: ATLAS/CONFIG/src/Makefile
-===================================================================
---- ATLAS.orig/CONFIG/src/Makefile
-+++ ATLAS/CONFIG/src/Makefile
-@@ -260,6 +260,11 @@ IRun_BINDP :
- redir=config0.out
- - cat config0.out
-
-+IRun_GAS_AARCH64 :
-+ $(CC) $(CCFLAGS) -o xprobe_gas_aarch64 $(SRCdir)/backend/probe_this_asm.c $(SRCdir)/backend/probe_gas_aarch64.S
-+ $(MAKE) $(atlrun) atldir=$(mydir) exe=xprobe_gas_aarch64 args="$(args)" \
-+ redir=config0.out
-+ - cat config0.out
- IRun_GAS_S390 :
- $(CC) $(CCFLAGS) -o xprobe_gas_s390 $(SRCdir)/backend/probe_this_asm.c $(SRCdir)/backend/probe_gas_s390.S
- $(MAKE) $(atlrun) atldir=$(mydir) exe=xprobe_gas_s390 args="$(args)" \
-Index: ATLAS/CONFIG/src/SpewMakeInc.c
-===================================================================
---- ATLAS.orig/CONFIG/src/SpewMakeInc.c
-+++ ATLAS/CONFIG/src/SpewMakeInc.c
-@@ -391,6 +391,8 @@ char *GetPtrbitsFlag(enum OSTYPE OS, enu
-
- if (MachIsIA64(arch))
- return(sp);
-+ if (MachIsAARCH64(arch))
-+ return(sp);
- if (MachIsMIPS(arch))
- return((ptrbits == 64) ? "-mabi=64" : "-mabi=n32");
- if (MachIsS390(arch))
-Index: ATLAS/CONFIG/src/atlcomp.txt
-===================================================================
---- ATLAS.orig/CONFIG/src/atlcomp.txt
-+++ ATLAS/CONFIG/src/atlcomp.txt
-@@ -267,6 +267,17 @@ MACH=ARMv7 OS=ALL LVL=1000 COMPS=dmc,dkc
- MACH=ARMv7 OS=ALL LVL=1000 COMPS=f77
- 'gfortran' '-mcpu=cortex-a8 -mfpu=vfpv3 -mfloat-abi=softfp -O'
- #
-+# AArch64 defaults
-+#
-+MACH=AARCH64 OS=ALL LVL=1000 COMPS=xcc
-+ 'gcc' '-O2'
-+MACH=AARCH64 OS=ALL LVL=1000 COMPS=smc,skc,gcc,icc
-+ 'gcc' '-O2'
-+MACH=AARCH64 OS=ALL LVL=1000 COMPS=dmc,dkc
-+ 'gcc' '-O2'
-+MACH=AARCH64 OS=ALL LVL=1000 COMPS=f77
-+ 'gfortran' '-O'
-+#
- # Generic defaults
- #
- MACH=ALL OS=ALL LVL=5 COMPS=icc,smc,dmc,skc,dkc,xcc,gcc
-Index: ATLAS/CONFIG/src/atlconf_misc.c
-===================================================================
---- ATLAS.orig/CONFIG/src/atlconf_misc.c
-+++ ATLAS/CONFIG/src/atlconf_misc.c
-@@ -563,6 +563,7 @@ enum ARCHFAM ProbeArchFam(char *targ)
- else if (strstr(res, "ia64")) fam = AFIA64;
- else if (strstr(res, "mips")) fam = AFMIPS;
- else if (strstr(res, "arm")) fam = AFARM;
-+ else if (strstr(res, "aarch64")) fam = AFAARCH64;
- else if (strstr(res, "s390")) fam = AFS390;
- else if ( strstr(res, "i686") || strstr(res, "i586") ||
- strstr(res, "i486") || strstr(res, "i386") ||
-@@ -588,6 +589,7 @@ enum ARCHFAM ProbeArchFam(char *targ)
- strstr(res, "x86_64") ) fam = AFX86;
- else if (strstr(res, "mips")) fam = AFMIPS;
- else if (strstr(res, "arm")) fam = AFARM;
-+ else if (strstr(res, "aarch64")) fam = AFAARCH64;
- else if (strstr(res, "s390")) fam = AFS390;
- free(res);
- }
-Index: ATLAS/CONFIG/src/backend/Make.ext
-===================================================================
---- ATLAS.orig/CONFIG/src/backend/Make.ext
-+++ ATLAS/CONFIG/src/backend/Make.ext
-@@ -57,6 +57,8 @@ probe_gas_arm.S : $(basf)
- $(extC) -b $(basf) -o probe_gas_arm.S rout=probe_gas_arm.S
- probe_gas_s390.S : $(basf)
- $(extC) -b $(basf) -o probe_gas_s390.S rout=probe_gas_s390.S
-+probe_gas_aarch64.S : $(basf)
-+ $(extC) -b $(basf) -o probe_gas_aarch64.S rout=probe_gas_aarch64.S
- probe_AVXMAC.S : $(basf)
- $(extC) -b $(basf) -o probe_AVXMAC.S rout=probe_AVXMAC.S
- probe_AVXFMA4.S : $(basf)
-Index: ATLAS/CONFIG/src/backend/archinfo_linux.c
-===================================================================
---- ATLAS.orig/CONFIG/src/backend/archinfo_linux.c
-+++ ATLAS/CONFIG/src/backend/archinfo_linux.c
-@@ -267,6 +267,14 @@ enum MACHTYPE ProbeArch()
- free(res);
- }
- break;
-+ case AFAARCH64:
-+ res = atlsys_1L(NULL, "fgrep 'Processor' /proc/cpuinfo", 0, 0);
-+ if (res)
-+ {
-+ if (strstr(res, "AArch64")) mach = AARCH64;
-+ free(res);
-+ }
-+ break;
- default:
- #if 0
- if (!CmndOneLine(NULL, "fgrep 'cpu family' /proc/cpuinfo", res))
-Index: ATLAS/CONFIG/src/backend/probe_gas_aarch64.S
-===================================================================
---- /dev/null
-+++ ATLAS/CONFIG/src/backend/probe_gas_aarch64.S
-@@ -0,0 +1,14 @@
-+#define ATL_GAS_AARCH64
-+#include "atlas_asm.h"
-+#
-+# Linux AArch64 assembler for:
-+# int asm_probe(int i)
-+# RETURNS: i*3
-+#
-+.text
-+.globl ATL_asmdecor(asm_probe)
-+.type ATL_asmdecor(asm_probe), %function
-+ATL_asmdecor(asm_probe):
-+ add w0, w0, w0, LSL #1
-+ ret
-+.size ATL_asmdecor(asm_probe),.-ATL_asmdecor(asm_probe)
-Index: ATLAS/CONFIG/src/probe_comp.c
-===================================================================
---- ATLAS.orig/CONFIG/src/probe_comp.c
-+++ ATLAS/CONFIG/src/probe_comp.c
-@@ -582,7 +582,7 @@ char *GetPtrbitsFlag(enum OSTYPE OS, enu
- char *sp = "";
- int i, j, k;
-
-- if (MachIsIA64(arch))
-+ if (MachIsIA64(arch) || MachIsAARCH64(arch))
- return(sp);
- if (MachIsMIPS(arch))
- return((ptrbits == 64) ? "-mabi=64" : "-mabi=n32");
-Index: ATLAS/include/atlas_genparse.h
-===================================================================
---- ATLAS.orig/include/atlas_genparse.h
-+++ ATLAS/include/atlas_genparse.h
-@@ -6,13 +6,13 @@
- #include <assert.h>
- #include <string.h>
- #include <ctype.h>
--#define NASMD 9
-+#define NASMD 10
- enum ASMDIA
- {ASM_None=0, gas_x86_32, gas_x86_64, gas_sparc, gas_ppc, gas_parisc,
-- gas_mips, gas_arm, gas_s390};
-+ gas_mips, gas_arm, gas_s390, gas_aarch64};
- static char *ASMNAM[NASMD] =
- {"", "GAS_x8632", "GAS_x8664", "GAS_SPARC", "GAS_PPC", "GAS_PARISC",
-- "GAS_MIPS", "GAS_ARM", "GAS_S390"};
-+ "GAS_MIPS", "GAS_ARM", "GAS_S390", "GAS_AARCH64"};
- /*
- * Basic data structure for forming queues with some minimal info
- */
diff --git a/atlas-affinity.patch b/atlas-affinity.patch
deleted file mode 100644
index 2a15d4d..0000000
--- a/atlas-affinity.patch
+++ /dev/null
@@ -1,17 +0,0 @@
-diff -up wrk/src/threads/ATL_thread_start.c.wrk wrk/src/threads/ATL_thread_start.c
---- wrk/src/threads/ATL_thread_start.c.wrk 2013-09-23 13:46:51.881085276 +0200
-+++ wrk/src/threads/ATL_thread_start.c 2013-09-24 16:13:59.021065418 +0200
-@@ -101,9 +101,10 @@ int ATL_thread_start(ATL_thread_t *thr,
- ATL_assert(!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED));
- pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); /* no chk, OK to fail */
- #ifdef ATL_PAFF_SETAFFNP
-- CPU_ZERO(&cpuset);
-- CPU_SET(affID, &cpuset);
-- ATL_assert(!pthread_attr_setaffinity_np(&attr, sizeof(cpuset), &cpuset));
-+ //affinity crashes a machine with fewer processors than the builder
-+ //CPU_ZERO(&cpuset);
-+ //CPU_SET(affID, &cpuset);
-+ //ATL_assert(!pthread_attr_setaffinity_np(&attr, sizeof(cpuset), &cpuset));
- #elif defined(ATL_PAFF_SETPROCNP)
- ATL_assert(!pthread_attr_setprocessor_np(&attr, (pthread_spu_t)affID,
- PTHREAD_BIND_FORCED_NP));
diff --git a/atlas-fedora-arm.patch b/atlas-fedora-arm.patch
deleted file mode 100644
index 22a9889..0000000
--- a/atlas-fedora-arm.patch
+++ /dev/null
@@ -1,50 +0,0 @@
---- CONFIG/include/atlconf.h 2011-05-14 13:33:24.000000000 -0400
-+++ CONFIG/include/atlconf.h.new 2011-08-30 14:25:41.427136391 -0400
-@@ -16,7 +16,7 @@
-
- enum ARCHFAM {AFOther=0, AFPPC, AFSPARC, AFALPHA, AFX86, AFIA64, AFMIPS};
-
--#define NMACH 37
-+#define NMACH 38
- static char *machnam[NMACH] =
- {"UNKNOWN", "POWER3", "POWER4", "POWER5", "PPCG4", "PPCG5",
- "POWER6", "POWER7",
-@@ -25,7 +25,7 @@
- "Efficeon", "K7", "HAMMER", "AMD64K10h", "UNKNOWNx86",
- "IA64Itan", "IA64Itan2",
- "USI", "USII", "USIII", "USIV", "UST2", "UnknownUS",
-- "MIPSR1xK", "MIPSICE9"};
-+ "MIPSR1xK", "MIPSICE9", "ARM"};
- enum MACHTYPE {MACHOther, IbmPwr3, IbmPwr4, IbmPwr5, PPCG4, PPCG5,
- IbmPwr6, IbmPwr7,
- IntP5, IntP5MMX, IntPPRO, IntPII, IntPIII, IntPM, IntCoreS,
-@@ -34,7 +34,8 @@
- IA64Itan, IA64Itan2,
- SunUSI, SunUSII, SunUSIII, SunUSIV, SunUST2, SunUSX,
- MIPSR1xK, /* includes R10K, R12K, R14K, R16K */
-- MIPSICE9 /* SiCortex ICE9 -- like MIPS5K */
-+ MIPSICE9, /* SiCortex ICE9 -- like MIPS5K */
-+ ARM
- };
- #define MachIsX86(mach_) \
- ( (mach_) >= IntP5 && (mach_) <= x86X )
-@@ -51,6 +52,8 @@
- #endif
- #define MachIsPPC(mach_) \
- ( (mach_) >= PPCG4 && (mach_) <= PPCG5 )
-+#define MachIsARM(mach_) \
-+ ( (mach_) == ARM )
-
- static char *f2c_namestr[5] = {"UNKNOWN","Add_", "Add__", "NoChange", "UpCase"};
- static char *f2c_intstr[5] =
---- CONFIG/src/probe_comp.c 2011-05-14 13:33:24.000000000 -0400
-+++ CONFIG/src/probe_comp.c.new 2011-08-30 14:28:31.103015151 -0400
-@@ -507,6 +507,8 @@
-
- if (MachIsIA64(arch))
- return(sp);
-+ if (MachIsARM(arch))
-+ return(sp);
- if (MachIsMIPS(arch))
- return((ptrbits == 64) ? "-mabi=64" : "-mabi=n32");
- if (!CompIsGcc(comp))
diff --git a/atlas-fedora_shared.patch b/atlas-fedora_shared.patch
deleted file mode 100644
index 98caa61..0000000
--- a/atlas-fedora_shared.patch
+++ /dev/null
@@ -1,111 +0,0 @@
---- makes/Make.lib 2008-06-06 20:57:46.000000000 -0400
-+++ makes/Make.lib.new 2008-12-21 15:36:21.000000000 -0500
-@@ -3,6 +3,8 @@
- #
- # override with libatlas.so only when atlas is built to one lib
- #
-+so_ver_major=3
-+so_ver = $(so_ver_major).0
- DYNlibs = liblapack.so libf77blas.so libcblas.so libatlas.so
- PTDYNlibs = liblapack.so libptf77blas.so libptcblas.so libatlas.so
- CDYNlibs = liblapack.so libcblas.so libatlas.so
-@@ -32,38 +34,78 @@
- mv $(tarnam).tar.gz $(tarnam).tgz
-
- ptshared :
-- - rm -f libatlas.so liblapack.so
-- $(MAKE) libatlas.so liblapack.so libptf77blas.so libf77blas.so \
-- libptcblas.so libcblas.so liblapack.so
-+ - rm -f libatlas.so* liblapack.so* \
-+ lib*blas.so* libclapack.so*
-+ $(MAKE) libatlas.so libcblas.so libptf77blas.so libf77blas.so \
-+ libptcblas.so liblapack.so libclapack.so
- shared :
-- - rm -f libatlas.so liblapack.so
-- $(MAKE) libatlas.so liblapack.so libf77blas.so libcblas.so liblapack.so
-+ - rm -f libatlas.so liblapack.so \
-+ libatlas.so.$(so_ver) liblapack.so.$(so_ver)
-+ $(MAKE) libatlas.so libcblas.so libf77blas.so liblapack.so libclapack.so
- cptshared :
-- - rm -f libatlas.so libclapack.so
-- $(MAKE) libatlas.so libclapack.so libptcblas.so libcblas.so
-+ - rm -f libatlas.so libclapack.so \
-+ libatlas.so.$(so_ver) libclapack.so.$(so_ver)
-+ $(MAKE) libatlas.so libptcblas.so libcblas.so libclapack.so
- cshared :
-- - rm -f libatlas.so libclapack.so
-- $(MAKE) libatlas.so libclapack.so libcblas.so
-+ - rm -f libatlas.so libclapack.so \
-+ libatlas.so.$(so_ver) libclapack.so.$(so_ver)
-+ $(MAKE) libatlas.so libcblas.so libclapack.so
-
- libatlas.so : libatlas.a
-- ld $(LDFLAGS) -shared -soname libatlas.so -o libatlas.so \
-- --whole-archive libatlas.a --no-whole-archive -lc $(LIBS)
-+ mkdir static_libs ; cd static_libs ; ar x ../libatlas.a ; cd ../
-+ gcc $(LDFLAGS) -shared -Wl,-soname=libatlas.so.$(so_ver_major) \
-+ -o libatlas.so.$(so_ver) static_libs/*.o -lc $(LIBS)
-+ rm -rf static_libs
-+ ln -s ./libatlas.so.$(so_ver) libatlas.so.$(so_ver_major)
-+ ln -s ./libatlas.so.$(so_ver) libatlas.so
- liblapack.so : liblapack.a
-- ld $(LDFLAGS) -shared -soname $@ -o $@ --whole-archive \
-- liblapack.a --no-whole-archive $(F77SYSLIB)
-+ mkdir static_libs ; cd static_libs ; ar x ../liblapack.a ; cd ../
-+ gcc $(LDFLAGS) -shared -Wl,-soname=liblapack.so.$(so_ver_major) \
-+ -o liblapack.so.$(so_ver) static_libs/*.o $(F77SYSLIB) \
-+ libf77blas.so.$(so_ver_major) libcblas.so.$(so_ver_major)
-+ rm -rf static_libs
-+ ln -s ./liblapack.so.$(so_ver) liblapack.so.$(so_ver_major)
-+ ln -s ./liblapack.so.$(so_ver) liblapack.so
- libclapack.so : libclapack.a
-- ld $(LDFLAGS) -shared -soname liblapack.so -o liblapack.so \
-- --whole-archive libclapack.a
-+ mkdir static_libs ; cd static_libs ; ar x ../libclapack.a ; cd ../
-+ gcc $(LDFLAGS) -shared -Wl,-soname=libclapack.so.$(so_ver_major) \
-+ -o libclapack.so.$(so_ver) static_libs/*.o \
-+ libcblas.so.$(so_ver_major) -lc $(LIBS)
-+ rm -rf static_libs
-+ ln -s ./libclapack.so.$(so_ver) libclapack.so.$(so_ver_major)
-+ ln -s ./libclapack.so.$(so_ver) libclapack.so
- libptf77blas.so : libptf77blas.a
-- ld $(LDFLAGS) -shared -soname $@ -o $@ --whole-archive libptf77blas.a \
-- --no-whole-archive $(F77SYSLIB)
-+ mkdir static_libs ; cd static_libs ; ar x ../libptf77blas.a ; cd ../
-+ gcc $(LDFLAGS) -shared -Wl,-soname=libptf77blas.so.$(so_ver_major) \
-+ -o libptf77blas.so.$(so_ver) static_libs/*.o \
-+ libatlas.so.$(so_ver) $(F77SYSLIB)
-+ rm -rf static_libs
-+ ln -s ./libptf77blas.so.$(so_ver) libptf77blas.so.$(so_ver_major)
-+ ln -s ./libptf77blas.so.$(so_ver) libptf77blas.so
- libf77blas.so : libf77blas.a
-- ld $(LDFLAGS) -shared -soname $@ -o $@ --whole-archive libf77blas.a \
-- --no-whole-archive $(F77SYSLIB)
-+ mkdir static_libs ; cd static_libs ; ar x ../libf77blas.a ; cd ../
-+ gcc $(LDFLAGS) -shared -Wl,-soname=libf77blas.so.$(so_ver_major) \
-+ -o libf77blas.so.$(so_ver) static_libs/*.o \
-+ libatlas.so.$(so_ver) $(F77SYSLIB)
-+ rm -rf static_libs
-+ ln -s ./libf77blas.so.$(so_ver) libf77blas.so.$(so_ver_major)
-+ ln -s ./libf77blas.so.$(so_ver) libf77blas.so
- libptcblas.so : libptcblas.a
-- ld $(LDFLAGS) -shared -soname $@ -o $@ --whole-archive libptcblas.a
-+ mkdir static_libs ; cd static_libs ; ar x ../libptcblas.a ; cd ../
-+ gcc $(LDFLAGS) -shared -Wl,-soname=libptcblas.so.$(so_ver_major) \
-+ -o libptcblas.so.$(so_ver) static_libs/*.o \
-+ libatlas.so.$(so_ver) -lc $(LIBS)
-+ rm -rf static_libs
-+ ln -s ./libptcblas.so.$(so_ver) libptcblas.so.$(so_ver_major)
-+ ln -s ./libptcblas.so.$(so_ver) libptcblas.so
- libcblas.so : libcblas.a
-- ld $(LDFLAGS) -shared -soname $@ -o $@ --whole-archive libcblas.a
-+ mkdir static_libs ; cd static_libs ; ar x ../libcblas.a ; cd ../
-+ gcc $(LDFLAGS) -shared -Wl,-soname=libcblas.so.$(so_ver_major) \
-+ -o libcblas.so.$(so_ver) static_libs/*.o \
-+ libatlas.so.$(so_ver) -lc $(LIBS)
-+ rm -rf static_libs
-+ ln -s ./libcblas.so.$(so_ver) libcblas.so.$(so_ver_major)
-+ ln -s ./libcblas.so.$(so_ver) libcblas.so
- #
- # Builds one shared lib from all ATLAS files
- #
diff --git a/atlas-new_archdef_for_ppc64le.patch b/atlas-new_archdef_for_ppc64le.patch
deleted file mode 100644
index 0356786..0000000
--- a/atlas-new_archdef_for_ppc64le.patch
+++ /dev/null
@@ -1,32 +0,0 @@
-Subject: atlas new archdef for ppc64le
-From: Michel Normand <normand(a)linux.vnet.ibm.com>
-Date: Sun, 13 Jun 2014 18:02:47 +0200
-
-Need to define different archdef names
-for ppc64 (that is Big Endian) and ppc64le (that is Little Endian).
-This is already done upstream in atlas 3.11.30 with issue
-https://sourceforge.net/p/math-atlas/patches/66/
-
-Required at least as long as I need the bypass of
-atlas.3.10.2-ppc64le_do_not_use_files_with_lvx.patch
-
-Signed-off-by: Michel Normand <normand(a)linux.vnet.ibm.com>
----
- CONFIG/src/SpewMakeInc.c | 4 ++++
- 1 file changed, 4 insertions(+)
-
-Index: ATLAS/CONFIG/src/SpewMakeInc.c
-===================================================================
---- ATLAS.orig/CONFIG/src/SpewMakeInc.c
-+++ ATLAS/CONFIG/src/SpewMakeInc.c
-@@ -542,6 +542,10 @@ int main(int nargs, char **args)
- fprintf(fpout, "# -------------------------------------------------\n");
- fprintf(fpout, " ARCH = %s", machnam[mach]);
- fprintf(fpout, "%d", ptrbits);
-+ /* for ppc64le archi add 'LE' characters */
-+ #if defined(__powerpc64__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
-+ fprintf(fpout, "%s", "LE");
-+ #endif
- if (ISAX)
- fprintf(fpout, "%s", ISAXNAM[ISAX]);
- if (!USEIEEE)
diff --git a/atlas-sparc-linux.patch b/atlas-sparc-linux.patch
deleted file mode 100644
index d865a0f..0000000
--- a/atlas-sparc-linux.patch
+++ /dev/null
@@ -1,95 +0,0 @@
-diff -uNr ATLAS.orig/CONFIG/src/backend/archinfo_linux.c ATLAS/CONFIG/src/backend/archinfo_linux.c
---- ATLAS.orig/CONFIG/src/backend/archinfo_linux.c 2010-02-01 23:28:58.000000000 +0000
-+++ ATLAS/CONFIG/src/backend/archinfo_linux.c 2010-02-02 22:38:31.000000000 +0000
-@@ -145,14 +145,12 @@
- * Add these back if we get machine access and can test
- */
- case AFSPARC: /* don't know here anymore */
-- #if 0
- if ( !CmndOneLine(NULL, "fgrep cpu /proc/cpuinfo", res) )
- {
-- if (strstr(res, "UltraSparc II")) mach = SunUS2;
-- else if (strstr(res, "UltraSparc I")) mach = SunUS1;
-- else if (strstr(res, "UltraSparc")) mach = SunUSX;
-+ if (strstr(res, "UltraSparc II")) mach = SunUSII;
-+ else if (strstr(res, "UltraSparc I")) mach = SunUSI;
-+ else if (strstr(res, "UltraSparc")) mach = SunUSII;
- }
-- #endif
- break;
- case AFALPHA:
- #if 0
-@@ -196,6 +194,11 @@
- reslns = CmndResults(NULL, "grep '^processor' /proc/cpuinfo");
- if (reslns) ncpu = fNumLines(reslns);
- }
-+ if (__sparc__)
-+ {
-+ reslns = CmndResults(NULL, "grep '^CPU.*online' /proc/cpuinfo");
-+ if (reslns) ncpu = fNumLines(reslns);
-+ }
- return(ncpu);
- }
-
-diff -uNr ATLAS.orig/tune/blas/gemm/CASES/ATL_dmm4x4x2_US.c ATLAS/tune/blas/gemm/CASES/ATL_dmm4x4x2_US.c
---- ATLAS.orig/tune/blas/gemm/CASES/ATL_dmm4x4x2_US.c 2010-02-01 23:29:23.000000000 +0000
-+++ ATLAS/tune/blas/gemm/CASES/ATL_dmm4x4x2_US.c 2010-02-01 23:30:07.000000000 +0000
-@@ -95,6 +95,11 @@
- #define incBm %g3
- #define incBn %g4
-
-+#if defined(__sparc__) && defined(__arch64__)
-+ .register %g2, #scratch
-+ .register %g3, #scratch
-+#endif
-+
- #ifdef DCPLX
- #define incCm 64
- #define CSH 4
-diff -uNr ATLAS.orig/tune/blas/gemm/CASES/ATL_dmm4x4x8_US.c ATLAS/tune/blas/gemm/CASES/ATL_dmm4x4x8_US.c
---- ATLAS.orig/tune/blas/gemm/CASES/ATL_dmm4x4x8_US.c 2010-02-01 23:29:24.000000000 +0000
-+++ ATLAS/tune/blas/gemm/CASES/ATL_dmm4x4x8_US.c 2010-02-01 23:30:08.000000000 +0000
-@@ -135,6 +135,11 @@
- #define pfB %i2 /* aliased with ldab */
- #endif
-
-+#if defined(__sparc__) && defined(__arch64__)
-+ .register %g2, #scratch
-+ .register %g3, #scratch
-+#endif
-+
- #ifdef DCPLX
- #define CMUL(arg_) ((arg_)*2)
- #define incCm 64
-diff -uNr ATLAS.orig/tune/blas/gemm/CASES/ATL_smm4x4x2_US.c ATLAS/tune/blas/gemm/CASES/ATL_smm4x4x2_US.c
---- ATLAS.orig/tune/blas/gemm/CASES/ATL_smm4x4x2_US.c 2010-02-01 23:29:25.000000000 +0000
-+++ ATLAS/tune/blas/gemm/CASES/ATL_smm4x4x2_US.c 2010-02-01 23:30:09.000000000 +0000
-@@ -93,6 +93,12 @@
- #define rC23 %f30
- #define rC33 %f31
- #define FSIZE 64
-+
-+#if defined(__sparc__) && defined(__arch64__)
-+ .register %g2, #scratch
-+ .register %g3, #scratch
-+#endif
-+
- #ifdef SCPLX
- #define CSH 3
- #define CMUL(arg_) ((arg_)*2)
-diff -uNr ATLAS.orig/tune/blas/gemm/CASES/ATL_smm4x4x72_US.c ATLAS/tune/blas/gemm/CASES/ATL_smm4x4x72_US.c
---- ATLAS.orig/tune/blas/gemm/CASES/ATL_smm4x4x72_US.c 2010-02-01 23:29:25.000000000 +0000
-+++ ATLAS/tune/blas/gemm/CASES/ATL_smm4x4x72_US.c 2010-02-01 23:30:09.000000000 +0000
-@@ -108,6 +108,12 @@
- #define rC23 %f30
- #define rC33 %f31
- #define FSIZE 64
-+
-+#if defined(__sparc__) && defined(__arch64__)
-+ .register %g2, #scratch
-+ .register %g3, #scratch
-+#endif
-+
- #ifdef SCPLX
- #define CSH 3
- #define CMUL(arg_) ((arg_)*2)
diff --git a/atlas.3.10.2-add_power8_cpu.patch b/atlas.3.10.2-add_power8_cpu.patch
deleted file mode 100644
index 7b58353..0000000
--- a/atlas.3.10.2-add_power8_cpu.patch
+++ /dev/null
@@ -1,131 +0,0 @@
-From: Michel Normand <normand(a)linux.vnet.ibm.com>
-Subject: atlas.3.10.2 add power8 cpu
-Date: Thu, 18 Sep 2014 15:13:24 +0200
-
-atlas.3.10.2 add Power8 cpu
-tracked upstream by issue 67
-https://sourceforge.net/p/math-atlas/patches/67/
-
-Signed-off-by: Michel Normand <normand(a)linux.vnet.ibm.com>
----
- CONFIG/ARCHS/Make.ext | 7 +++++++
- CONFIG/include/atlconf.h | 6 +++---
- CONFIG/src/atlcomp.txt | 6 ++++++
- CONFIG/src/backend/archinfo_aix.c | 2 ++
- CONFIG/src/backend/archinfo_linux.c | 1 +
- include/atlas_pca.h | 2 +-
- 6 files changed, 20 insertions(+), 4 deletions(-)
-
-Index: ATLAS/CONFIG/ARCHS/Make.ext
-===================================================================
---- ATLAS.orig/CONFIG/ARCHS/Make.ext
-+++ ATLAS/CONFIG/ARCHS/Make.ext
-@@ -33,6 +33,7 @@ files = AMD64K10h32SSE3.tar.bz2 AMD64K10
- MIPSR1xK64.tar.bz2 Makefile P432SSE2.tar.bz2 P4E32SSE3.tar.bz2 \
- P4E64SSE3.tar.bz2 PIII32SSE1.tar.bz2 POWER432.tar.bz2 \
- POWER464.tar.bz2 POWER564.tar.bz2 POWER764VSX.tar.bz2 \
-+ POWER864VSX.tar.bz2 \
- PPCG432AltiVec.tar.bz2 PPCG532AltiVec.tar.bz2 PPCG564AltiVec.tar.bz2 \
- PPRO32.tar.bz2 USIII32.tar.bz2 USIII64.tar.bz2 USIV32.tar.bz2 \
- USIV64.tar.bz2 UST232.tar.bz2 UST264.tar.bz2 atlas_test1.1.3.tar.bz2 \
-@@ -308,6 +309,12 @@ POWER764VSX.tar.bz2 : $(basdr)/POWER764V
- /tmp/POWER764VSX.tar POWER764VSX
- bzip2 /tmp/POWER764VSX.tar
- mv /tmp/POWER764VSX.tar.bz2 ./.
-+POWER864VSX.tar.bz2 : $(basdr)/POWER864VSX
-+ - rm -f /tmp/POWER864VSX.tar /tmp/POWER864VSX.tar.bz2
-+ cd $(basdr) ; tar --dereference --exclude 'CVS' -c -f \
-+ /tmp/POWER864VSX.tar POWER864VSX
-+ bzip2 /tmp/POWER864VSX.tar
-+ mv /tmp/POWER864VSX.tar.bz2 ./.
- IBMz1032.tar.bz2 : $(basdr)/IBMz1032
- - rm -f /tmp/IBMz1032.tar /tmp/IBMz1032.tar.bz2
- cd $(basdr) ; tar --dereference --exclude 'CVS' -c -f \
-Index: ATLAS/CONFIG/include/atlconf.h
-===================================================================
---- ATLAS.orig/CONFIG/include/atlconf.h
-+++ ATLAS/CONFIG/include/atlconf.h
-@@ -18,10 +18,10 @@ enum OSTYPE {OSOther=0, OSLinux, OSSunOS
- enum ARCHFAM {AFOther=0, AFPPC, AFSPARC, AFALPHA, AFX86, AFIA64, AFMIPS,
- AFARM, AFS390};
-
--#define NMACH 52
-+#define NMACH 53
- static char *machnam[NMACH] =
- {"UNKNOWN", "POWER3", "POWER4", "POWER5", "PPCG4", "PPCG5",
-- "POWER6", "POWER7", "POWERe6500", "IBMz9", "IBMz10", "IBMz196",
-+ "POWER6", "POWER7", "POWER8", "POWERe6500", "IBMz9", "IBMz10", "IBMz196",
- "x86x87", "x86SSE1", "x86SSE2", "x86SSE3",
- "P5", "P5MMX", "PPRO", "PII", "PIII", "PM", "CoreSolo",
- "CoreDuo", "Core2Solo", "Core2", "Corei1", "Corei2", "Corei3",
-@@ -31,7 +31,7 @@ static char *machnam[NMACH] =
- "USI", "USII", "USIII", "USIV", "UST1", "UST2", "UnknownUS",
- "MIPSR1xK", "MIPSICE9", "ARMv7"};
- enum MACHTYPE {MACHOther, IbmPwr3, IbmPwr4, IbmPwr5, PPCG4, PPCG5,
-- IbmPwr6, IbmPwr7, Pwre6500,
-+ IbmPwr6, IbmPwr7, IbmPwr8, Pwre6500,
- IbmZ9, IbmZ10, IbmZ196, /* s390(x) in Linux */
- x86x87, x86SSE1, x86SSE2, x86SSE3, /* generic targets */
- IntP5, IntP5MMX, IntPPRO, IntPII, IntPIII, IntPM, IntCoreS,
-Index: ATLAS/CONFIG/src/atlcomp.txt
-===================================================================
---- ATLAS.orig/CONFIG/src/atlcomp.txt
-+++ ATLAS/CONFIG/src/atlcomp.txt
-@@ -190,6 +190,10 @@ MACH=PPCG5 OS=ALL LVL=1000 COMPS=dmc,icc
- 'gcc' '-mpowerpc64 -maltivec -mabi=altivec -mcpu=970 -mtune=970 -O2'
- MACH=PPCG5 OS=ALL LVL=1000 COMPS=skc
- 'gcc' '-mpowerpc64 -maltivec -mabi=altivec -mcpu=970 -mtune=970 -O2 -mvrsave'
-+MACH=POWER8 OS=ALL LVL=1010 COMPS=icc,smc,dmc,skc,dkc,xcc,gcc
-+ 'gcc' '-O2 -mvsx -mcpu=power8 -mtune=power8 -m64 -mvrsave -funroll-all-loops'
-+MACH=POWER8 OS=ALL LVL=1010 COMPS=f77
-+ 'gfortran' '-O2 -mvsx -mcpu=power8 -mtune=power8 -m64 -mvrsave -funroll-all-loops'
- MACH=POWER7 OS=ALL LVL=1010 COMPS=icc,smc,dmc,skc,dkc,xcc,gcc
- 'gcc' '-O2 -mvsx -mcpu=power7 -mtune=power7 -m64 -mvrsave -funroll-all-loops'
- MACH=POWER7 OS=ALL LVL=1010 COMPS=f77
-@@ -210,6 +214,8 @@ MACH=POWER4 OS=ALL LVL=1010 COMPS=icc,dm
- 'gcc' '-mcpu=power4 -mtune=power4 -O3 -fno-schedule-insns -fno-rerun-loop-opt'
- MACH=POWER4 OS=ALL LVL=1010 COMPS=f77
- 'xlf' '-qtune=pwr4 -qarch=pwr4 -O3 -qmaxmem=-1 -qfloat=hsflt'
-+MACH=POWER8 OS=ALL LVL=1010 COMPS=f77
-+ 'xlf' '-qtune=pwr8 -qarch=pwr8 -O3 -qmaxmem=-1 -qfloat=hsflt'
- #
- # IBM System z or zEnterprise.
- # These compiler flags given by IBM; -O3 -funroll-loops are chosen because
-Index: ATLAS/CONFIG/src/backend/archinfo_linux.c
-===================================================================
---- ATLAS.orig/CONFIG/src/backend/archinfo_linux.c
-+++ ATLAS/CONFIG/src/backend/archinfo_linux.c
-@@ -77,6 +77,7 @@ enum MACHTYPE ProbeArch()
- else if (strstr(res, "7455")) mach = PPCG4;
- else if (strstr(res, "PPC970FX")) mach = PPCG5;
- else if (strstr(res, "PPC970MP")) mach = PPCG5;
-+ else if (strstr(res, "POWER8")) mach = IbmPwr8;
- else if (strstr(res, "POWER7")) mach = IbmPwr7;
- else if (strstr(res, "POWER6")) mach = IbmPwr6;
- else if (strstr(res, "POWER5")) mach = IbmPwr5;
-Index: ATLAS/include/atlas_pca.h
-===================================================================
---- ATLAS.orig/include/atlas_pca.h
-+++ ATLAS/include/atlas_pca.h
-@@ -26,7 +26,7 @@
- #endif
- #elif defined(ATL_ARCH_POWER3) || defined(ATL_ARCH_POWER4) || \
- defined(ATL_ARCH_POWER5) || defined(ATL_ARCH_POWER6) || \
-- defined(ATL_ARCH_POWER7)
-+ defined(ATL_ARCH_POWER7) || defined(ATL_ARCH_POWER8)
- #ifdef __GNUC__
- #define ATL_membarrier __asm__ __volatile__ ("dcs")
- /* #define ATL_USEPCA 1 */
-Index: ATLAS/CONFIG/src/backend/archinfo_aix.c
-===================================================================
---- ATLAS.orig/CONFIG/src/backend/archinfo_aix.c
-+++ ATLAS/CONFIG/src/backend/archinfo_aix.c
-@@ -67,6 +67,8 @@ enum MACHTYPE ProbeArch()
- {
- if (strstr(res, "PowerPC_POWER5"))
- mach = IbmPwr5;
-+ else if (strstr(res, "PowerPC_POWER8"))
-+ mach = IbmPwr8;
- else if (strstr(res, "PowerPC_POWER7"))
- mach = IbmPwr7;
- else if (strstr(res, "PowerPC_POWER6"))
diff --git a/atlas.3.10.2-ppc64le_abiv2.patch b/atlas.3.10.2-ppc64le_abiv2.patch
deleted file mode 100644
index 6633d95..0000000
--- a/atlas.3.10.2-ppc64le_abiv2.patch
+++ /dev/null
@@ -1,220 +0,0 @@
-From: Michel Normand <normand(a)linux.vnet.ibm.com>
-Subject: atlas.3.10.2 ppc64le abiv2 patch
-Date: Mon, 28 Jul 2014 04:29:05 -0400
-
-atlas.3.10.2 abiv2 step2 complete the changes already present in atlas 3.10.2
-* still some files with opd ABI V1 to be disabled for ABI V2
- tune/blas/gemm/CASES/ATL_dmm4x4x32_ppc.c
- tune/blas/gemm/CASES/ATL_dmm4x4x80_ppc.c
- tune/blas/gemm/CASES/ATL_smm4x4x128_av.c
-
-atlas.3.10.2 ppc64le abiv2 step3
-* change offsets of parameters read from stack to avoid some segfaults.
- (values changes 120 => 104 and 128 => 112 identified by gdb investigation)
-
-Despite this step3 patch there are two Remaining problems for ppc64le archi:
-* TODO: still have seg-faults in console during build/check
-but is not critical (without make check) and rpm are generated on fedora.
-unable to investigate because of problem tracked by issue 950
-https://sourceforge.net/p/math-atlas/support-requests/950/
-
-* TODO: make check failure because xsslvtst execution failure
-related to vector assembly code that assumes big-endian env
-as written in ATL_cmm4x4x128_av.c and ATL_smm4x4x128_av.c.
-Would need significant work to support little-endian as per
-endianess comments of all PowerPC vector instructions in:
-https://www-01.ibm.com/chips/techlib/techlib.nsf/techdocs/FBFA164F824370F987256D6A006F424D/$file/vector_simd_pem.ppc.2005AUG23.pdf
-
-Signed-off-by: Michel Normand <normand(a)linux.vnet.ibm.com>
----
- tune/blas/gemm/CASES/ATL_cmm4x4x128_av.c | 7 +++++++
- tune/blas/gemm/CASES/ATL_dmm4x4x2pf_av.c | 7 +++++++
- tune/blas/gemm/CASES/ATL_dmm4x4x32_ppc.c | 9 ++++++++-
- tune/blas/gemm/CASES/ATL_dmm4x4x80_ppc.c | 20 ++++++++++++++++++--
- tune/blas/gemm/CASES/ATL_smm4x4x128_av.c | 23 ++++++++++++++++++++++-
- 5 files changed, 62 insertions(+), 4 deletions(-)
-
-Index: ATLAS/tune/blas/gemm/CASES/ATL_dmm4x4x32_ppc.c
-===================================================================
---- ATLAS.orig/tune/blas/gemm/CASES/ATL_dmm4x4x32_ppc.c
-+++ ATLAS/tune/blas/gemm/CASES/ATL_dmm4x4x32_ppc.c
-@@ -268,7 +268,7 @@ Mjoin(.,ATL_USERMM):
- .globl Mjoin(_,ATL_USERMM)
- Mjoin(_,ATL_USERMM):
- #else
-- #if defined(ATL_USE64BITS)
-+ #if defined(ATL_USE64BITS) && _CALL_ELF != 2
- /*
- * Official Program Descripter section, seg fault w/o it on Linux/PPC64
- */
-@@ -324,8 +324,15 @@ ATL_USERMM:
- #endif
-
- #ifdef ATL_USE64BITS
-+#if _CALL_ELF == 2
-+/* ABIv2 */
-+ ld pC0, 104(r1)
-+ ld incCn, 112(r1)
-+#else
-+/* ABIv1 */
- ld pC0, 120(r1)
- ld incCn, 128(r1)
-+#endif
- #elif defined(ATL_AS_OSX_PPC) || defined(ATL_AS_AIX_PPC)
- lwz pC0, 68(r1)
- lwz incCn, 72(r1)
-Index: ATLAS/tune/blas/gemm/CASES/ATL_dmm4x4x80_ppc.c
-===================================================================
---- ATLAS.orig/tune/blas/gemm/CASES/ATL_dmm4x4x80_ppc.c
-+++ ATLAS/tune/blas/gemm/CASES/ATL_dmm4x4x80_ppc.c
-@@ -170,13 +170,21 @@ void ATL_USERMM(const int M, const int N
- const TYPE beta, TYPE *C, const int ldc)
- (r10) 8(r1)
- *******************************************************************************
--64 bit ABIs:
-+64 bit ABIv1s:
- r3 r4 r5 r6/f1
- void ATL_USERMM(const int M, const int N, const int K, const TYPE alpha,
- r7 r8 r9 r10
- const TYPE *A, const int lda, const TYPE *B, const int ldb,
- f2 120(r1) 128(r1)
- const TYPE beta, TYPE *C, const int ldc)
-+
-+64 bit ABIv2s:
-+ r3 r4 r5 r6/f1
-+void ATL_USERMM(const int M, const int N, const int K, const TYPE alpha,
-+ r7 r8 r9 r10
-+ const TYPE *A, const int lda, const TYPE *B, const int ldb,
-+ f2 104(r1) 112(r1)
-+ const TYPE beta, TYPE *C, const int ldc)
- #endif
- #ifdef ATL_AS_AIX_PPC
- .csect .text[PR]
-@@ -202,7 +210,7 @@ Mjoin(.,ATL_USERMM):
- .globl Mjoin(_,ATL_USERMM)
- Mjoin(_,ATL_USERMM):
- #else
-- #if defined(ATL_USE64BITS)
-+ #if defined(ATL_USE64BITS) && _CALL_ELF != 2
- /*
- * Official Program Descripter section, seg fault w/o it on Linux/PPC64
- */
-@@ -257,9 +265,17 @@ ATL_USERMM:
- #endif
- #endif
-
-+
- #if defined (ATL_USE64BITS)
-+#if _CALL_ELF == 2
-+/* ABIv2 */
-+ ld pC0, 104(r1)
-+ ld incCn, 112(r1)
-+#else
-+/* ABIv1 */
- ld pC0, 120(r1)
- ld incCn, 128(r1)
-+#endif
- #elif defined(ATL_AS_OSX_PPC) || defined(ATL_AS_AIX_PPC)
- lwz pC0, 68(r1)
- lwz incCn, 72(r1)
-Index: ATLAS/tune/blas/gemm/CASES/ATL_smm4x4x128_av.c
-===================================================================
---- ATLAS.orig/tune/blas/gemm/CASES/ATL_smm4x4x128_av.c
-+++ ATLAS/tune/blas/gemm/CASES/ATL_smm4x4x128_av.c
-@@ -196,7 +196,7 @@ void ATL_USERMM(const int M, const int N
- .globl Mjoin(_,ATL_USERMM)
- Mjoin(_,ATL_USERMM):
- #else
-- #if defined(ATL_USE64BITS)
-+ #if defined(ATL_USE64BITS) && _CALL_ELF != 2
- /*
- * Official Program Descripter section, seg fault w/o it on Linux/PPC64
- */
-@@ -221,8 +221,15 @@ ATL_USERMM:
- * kernel instead
- */
- #if defined (ATL_USE64BITS)
-+#if _CALL_ELF == 2
-+/* ABIv2 */
-+ ld r10, 104(r1)
-+ ld r5, 112(r1)
-+#else
-+/* ABIv1 */
- ld r10, 120(r1)
- ld r5, 128(r1)
-+#endif
- #elif defined(ATL_AS_OSX_PPC)
- lwz r10, 60(r1)
- lwz r5, 64(r1)
-@@ -285,8 +292,15 @@ ATL_USERMM:
- eqv r0, r0, r0 /* all 1s */
- ATL_WriteVRSAVE(r0) /* signal we use all vector regs */
- #if defined (ATL_USE64BITS)
-+#if _CALL_ELF == 2
-+ /* ABIv2 */
-+ ld pC0, FSIZE+104(r1)
-+ ld ldc, FSIZE+112(r1)
-+#else
-+ /* ABIv1 */
- ld pC0, FSIZE+120(r1)
- ld ldc, FSIZE+128(r1)
-+#endif
- #elif defined(ATL_AS_OSX_PPC)
- lwz pC0, FSIZE+60(r1)
- lwz ldc, FSIZE+64(r1)
-@@ -4258,8 +4272,15 @@ UNALIGNED_C:
- eqv r0, r0, r0 /* all 1s */
- ATL_WriteVRSAVE(r0) /* signal we use all vector regs */
- #if defined (ATL_USE64BITS)
-+#if _CALL_ELF == 2
-+ /* ABIv2 */
-+ ld pC0, FSIZE+104(r1)
-+ ld ldc, FSIZE+112(r1)
-+#else
-+ /* ABIv1 */
- ld pC0, FSIZE+120(r1)
- ld ldc, FSIZE+128(r1)
-+#endif
- #elif defined(ATL_AS_OSX_PPC)
- lwz pC0, FSIZE+60(r1)
- lwz ldc, FSIZE+64(r1)
-Index: ATLAS/tune/blas/gemm/CASES/ATL_cmm4x4x128_av.c
-===================================================================
---- ATLAS.orig/tune/blas/gemm/CASES/ATL_cmm4x4x128_av.c
-+++ ATLAS/tune/blas/gemm/CASES/ATL_cmm4x4x128_av.c
-@@ -258,8 +258,15 @@ ATL_USERMM:
- eqv r0, r0, r0 /* all 1s */
- ATL_WriteVRSAVE(r0) /* signal we use all vector regs */
- #if defined (ATL_USE64BITS)
-+#if _CALL_ELF == 2
-+/* ABIv2 */
-+ ld pC0, FSIZE+104(r1)
-+ ld ldc, FSIZE+112(r1)
-+#else
-+/* ABIv1 */
- ld pC0, FSIZE+120(r1)
- ld ldc, FSIZE+128(r1)
-+#endif
- #elif defined(ATL_AS_OSX_PPC)
- lwz pC0, FSIZE+60(r1)
- lwz ldc, FSIZE+64(r1)
-Index: ATLAS/tune/blas/gemm/CASES/ATL_dmm4x4x2pf_av.c
-===================================================================
---- ATLAS.orig/tune/blas/gemm/CASES/ATL_dmm4x4x2pf_av.c
-+++ ATLAS/tune/blas/gemm/CASES/ATL_dmm4x4x2pf_av.c
-@@ -405,8 +405,15 @@ Mjoin(_,ATL_USERMM):
- */
- #ifdef ATL_GAS_LINUX_PPC
- #ifdef ATL_USE64BITS
-+ #if _CALL_ELF == 2
-+ /* ABIv2 */
-+ ld pC0, 104(r1)
-+ ld incCn, 112(r1)
-+ #else
-+ /* ABIv1 */
- ld pC0, 120(r1)
- ld incCn, 128(r1)
-+ #endif
- #else
- lwz incCn, FSIZE+8(r1)
- #endif
diff --git a/atlas.3.10.2-ppc64le_do_not_use_files_with_lvx.patch b/atlas.3.10.2-ppc64le_do_not_use_files_with_lvx.patch
deleted file mode 100644
index a3a6607..0000000
--- a/atlas.3.10.2-ppc64le_do_not_use_files_with_lvx.patch
+++ /dev/null
@@ -1,151 +0,0 @@
-From: Michel Normand <normand(a)linux.vnet.ibm.com>
-Subject: atlas.3.10.2 ppc64le do not use files with lvx
-Date: Tue, 12 Aug 2014 16:07:06 +0200
-
-ppc64le do not use files with lvx
-This is a temporary patch as long as the related files
-are not ported yet to ppc64 little-endian.
-
-Warning: patch to be applied only for ppc64le architecture
-and will also need atlas-new_archdef_for_ppc64le.patch
-
-Signed-off-by: Michel Normand <normand(a)linux.vnet.ibm.com>
----
- tune/blas/gemm/CASES/ccases.flg | 6 +-----
- tune/blas/gemm/CASES/dcases.flg | 8 +-------
- tune/blas/gemm/CASES/dcases.vnb | 4 ----
- tune/blas/gemm/CASES/scases.flg | 9 +--------
- tune/blas/gemm/CASES/scases.vnb | 3 ---
- tune/blas/gemm/CASES/zcases.flg | 8 +-------
- 6 files changed, 4 insertions(+), 34 deletions(-)
-
-Index: ATLAS/tune/blas/gemm/CASES/ccases.flg
-===================================================================
---- ATLAS.orig/tune/blas/gemm/CASES/ccases.flg
-+++ ATLAS/tune/blas/gemm/CASES/ccases.flg
-@@ -1,5 +1,5 @@
- <ID> <flag> <mb> <nb> <kb> <muladd> <lat> <mu> <nu> <ku> <rout> "<Contributer>"
--24
-+22
- 304 192 4 3 8 0 4 4 3 8 ATL_mm4x3x8p.c "R. Clint Whaley" \
- gcc
- -mcpu=ultrasparc -mtune=ultrasparc -fomit-frame-pointer -O
-@@ -48,13 +48,9 @@ gcc
- 328 480 8 8 2 1 1 8 8 2 ATL_mm8x8x2.c "R. Clint Whaley" \
- gcc
- -fomit-frame-pointer -O2 -fno-tree-loop-optimize
--329 192 4 4 4 1 16 4 4 4 ATL_cmm4x4x128_av.c "R. Clint Whaley" \
--gcc
---x assembler-with-cpp
- 331 192 4 4 1 1 1 4 4 1 ATL_smm4x4xURx_mips.c "R. Clint Whaley" \
- gcc
- -x assembler-with-cpp -mips4
--332 192 8 2 4 1 0 8 2 4 ATL_smm8x2x4_av.c "IBM"
- 333 448 4 4 2 1 1 4 4 2 ATL_smm4x4x2pf_arm.c "R. Clint Whaley" \
- gcc
- -x assembler-with-cpp -mfpu=vfpv3
-Index: ATLAS/tune/blas/gemm/CASES/scases.flg
-===================================================================
---- ATLAS.orig/tune/blas/gemm/CASES/scases.flg
-+++ ATLAS/tune/blas/gemm/CASES/scases.flg
-@@ -1,5 +1,5 @@
- <ID> <flag> <mb> <nb> <kb> <muladd> <lat> <mu> <nu> <ku> <rout> "<Contributer>"
--25
-+22
- 304 192 4 3 8 0 4 4 3 8 ATL_mm4x3x8p.c "R. Clint Whaley" \
- gcc
- -mcpu=ultrasparc -mtune=ultrasparc -fomit-frame-pointer -O
-@@ -48,16 +48,9 @@ gcc
- 328 480 8 8 2 1 1 8 8 2 ATL_mm8x8x2.c "R. Clint Whaley" \
- gcc
- -fomit-frame-pointer -O2 -fno-tree-loop-optimize
--329 192 4 4 4 1 16 4 4 4 ATL_smm4x4x128_av.c "R. Clint Whaley" \
--gcc
---x assembler-with-cpp
--330 200 92 92 92 1 16 92 92 92 ATL_smm4x4x128_av.c "R. Clint Whaley" \
--gcc
---x assembler-with-cpp
- 331 192 4 4 1 1 1 4 4 1 ATL_smm4x4xURx_mips.c "R. Clint Whaley" \
- gcc
- -x assembler-with-cpp -mips4
--332 192 8 2 4 1 0 8 2 4 ATL_smm8x2x4_av.c "IBM"
- 333 448 4 4 2 1 1 4 4 2 ATL_smm4x4x2pf_arm.c "R. Clint Whaley" \
- gcc
- -x assembler-with-cpp -mfpu=vfpv3
-Index: ATLAS/tune/blas/gemm/CASES/scases.vnb
-===================================================================
---- ATLAS.orig/tune/blas/gemm/CASES/scases.vnb
-+++ ATLAS/tune/blas/gemm/CASES/scases.vnb
-@@ -31,9 +31,6 @@
- # Defaults: TA='t', TB='n', SSE=0, X87=0, LDBOT=1, RTKU=0, AOUTER=0,
- # KBMAX=KU, KBMIN=KU, BETAN1=0, RTMN=1
- #
--ID=1 ROUT='ATL_smm4x4x128_av.c' AUTH='R. Clint Whaley' MU=4 NU=4 KU=4 \
-- LDKB=1 LDBOT=1 KBMIN=4 KBMAX=128 ASM=GAS_PPC \
-- COMP='gcc' FLAGS='-x assembler-with-cpp'
- ID=2 ROUT='ATL_smm4x4x16_av.c' AUTH='R. Clint Whaley' MU=4 NU=4 KU=16 \
- LDKB=1 LDBOT=0 KBMIN=16 KBMAX=2048 ASM=GAS_SPARC \
- COMP='gcc' FLAGS='-x assembler-with-cpp'
-Index: ATLAS/tune/blas/gemm/CASES/dcases.flg
-===================================================================
---- ATLAS.orig/tune/blas/gemm/CASES/dcases.flg
-+++ ATLAS/tune/blas/gemm/CASES/dcases.flg
-@@ -1,5 +1,5 @@
- <ID> <flag> <mb> <nb> <kb> <muladd> <lat> <mu> <nu> <ku> <rout> "<Contributer>"
--32
-+30
- 306 192 4 3 8 0 4 4 3 8 ATL_mm4x3x8p.c "R. Clint Whaley" \
- gcc
- -mcpu=ultrasparc -mtune=ultrasparc -fomit-frame-pointer -O -fno-schedule-insns -fno-schedule-insns2
-@@ -79,12 +79,6 @@ gcc
- 336 192 4 4 1 1 1 4 4 1 ATL_dmm4x4xURx_mips.c "R. Clint Whaley" \
- gcc
- -x assembler-with-cpp -mips4
--337 192 4 4 1 1 16 4 4 1 ATL_dmm4x4x80_ppc.c "Whaley & Castaldo" \
--gcc
---x assembler-with-cpp
--338 192 8 4 2 1 0 8 4 2 ATL_dmm8x4x2_vsx.c "IBM" \
--gcc
---O3 -mvsx
- 339 448 4 4 2 1 1 4 4 2 ATL_dmm4x4x2pf_arm.c "R. Clint Whaley" \
- gcc
- -x assembler-with-cpp -mfpu=vfpv3
-Index: ATLAS/tune/blas/gemm/CASES/dcases.vnb
-===================================================================
---- ATLAS.orig/tune/blas/gemm/CASES/dcases.vnb
-+++ ATLAS/tune/blas/gemm/CASES/dcases.vnb
-@@ -53,10 +53,6 @@ ID=6 ROUT='ATL_dmm4x1x90_x87.c' AUTH='R
- ID=7 ROUT='ATL_dmm8x1x120_sse2.c' AUTH='R. Clint Whaley' \
- MU=8 NU=1 KU=1 KBMAX=512 ASM=GAS_x8664 BETAN1=1 \
- COMP='gcc' FLAGS='-m64 -x assembler-with-cpp'
--ID=70 ROUT='ATL_dmm4x4x80_ppc.c' AUTH='R. Clint Whaley' TA='T', TB='N' \
-- MU=4 NU=4 KU=1 KBMIN=1 KBMAX=80 ASM=GAS_PPC BETAN1=0 LDBOT=0 \
-- LDAB=0 LDISKB=1 RTN=1 RTM=1 RTK=0 \
-- COMP='gcc' FLAGS='-x assembler-with-cpp'
- ID=80 ROUT='ATL_dmm4x4x16r8_US.c' AUTH='R. Clint Whaley' TA='T', TB='N' \
- MU=4 NU=4 KU=24 KBMIN=24 KBMAX=512 ASM=GAS_SPARC BETAN1=0 \
- LDAB=0 RTK=1 RTN=1 RTM=1 LDBOT=0 LDISKB=1 LDAB=1 \
-Index: ATLAS/tune/blas/gemm/CASES/zcases.flg
-===================================================================
---- ATLAS.orig/tune/blas/gemm/CASES/zcases.flg
-+++ ATLAS/tune/blas/gemm/CASES/zcases.flg
-@@ -1,5 +1,5 @@
- <ID> <flag> <mb> <nb> <kb> <muladd> <lat> <mu> <nu> <ku> <rout> "<Contributer>"
--31
-+29
- 306 192 4 3 8 0 4 4 3 8 ATL_mm4x3x8p.c "R. Clint Whaley" \
- gcc
- -mcpu=ultrasparc -mtune=ultrasparc -fomit-frame-pointer -O -fno-schedule-insns -fno-schedule-insns2
-@@ -76,12 +76,6 @@ gcc
- 336 192 4 4 1 1 1 4 4 1 ATL_dmm4x4xURx_mips.c "R. Clint Whaley" \
- gcc
- -x assembler-with-cpp -mips4
--337 192 4 4 1 1 16 4 4 1 ATL_dmm4x4x80_ppc.c "Whaley & Castaldo" \
--gcc
---x assembler-with-cpp
--338 192 8 4 2 1 0 8 4 2 ATL_dmm8x4x2_vsx.c "IBM" \
--gcc
---O3 -mvsx
- 339 448 4 4 2 1 1 4 4 2 ATL_dmm4x4x2pf_arm.c "R. Clint Whaley" \
- gcc
- -x assembler-with-cpp -mfpu=vfpv3
diff --git a/atlas.spec b/atlas.spec
index 08c2767..5cbac4c 100644
--- a/atlas.spec
+++ b/atlas.spec
@@ -12,39 +12,49 @@ License: BSD
URL: http://math-atlas.sourceforge.net/
Source0: http://downloads.sourceforge.net/math-atlas/%{name}%{version}.tar.bz2
Source1: PPRO32.tgz
-#Source2: K7323DNow.tgz
-Source3: README.dist
-#Source4: USII64.tgz
-#Source5: USII32.tgz
-#Source6: IBMz1032.tgz
-#Source7: IBMz1064.tgz
-#Source8: IBMz19632.tgz
-#Source9: IBMz19664.tgz
+Source2: README.dist
#archdefs taken from debian:
-Source11: POWER332.tar.bz2
-Source12: IBMz932.tar.bz2
-Source13: IBMz964.tar.bz2
+Source3: POWER332.tar.bz2
+Source4: IBMz932.tar.bz2
+Source5: IBMz964.tar.bz2
#upstream arm uses softfp abi, fedora arm uses hard
-Source14: ARMv732NEON.tar.bz2
+Source6: ARMv732NEON.tar.bz2
#again, taken from debian
-Source15: IBMz1264.tar.bz2
-Source16: ARMa732.tar.bz2
+Source7: IBMz1264.tar.bz2
+Source8: ARMa732.tar.bz2
+
+#Provided By IBM
+Source9: IBMz1364VXZ.tar.bz2
+Source10: IBMz1464VXZ2.tar.bz2
+Source11: IBMz1564VXZ2.tar.bz2
-Patch2: atlas-fedora-arm.patch
# Properly pass -melf_* to the linker with -Wl, fixes FTBFS bug 817552
# https://sourceforge.net/tracker/?func=detail&atid=379484&aid=3555789&grou...
-Patch3: atlas-melf.patch
-Patch4: atlas-throttling.patch
+Patch1: atlas-melf.patch
+Patch2: atlas-throttling.patch
#credits Lukas Slebodnik
-Patch5: atlas-shared_libraries.patch
+Patch3: atlas-shared_libraries.patch
-Patch7: atlas-aarch64port.patch
-Patch8: atlas-genparse.patch
+Patch4: atlas-genparse.patch
# Unbundle LAPACK (BZ #1181369)
-Patch9: atlas.3.10.1-unbundle.patch
-Patch10: atlas-gcc10.patch
+Patch5: atlas.3.10.1-unbundle.patch
+Patch6: atlas-gcc10.patch
+
+
+#patches dealing with z{13,14,15}, provided by IBM
+Patch7: 0001-Avoid-c99-standard-compiler.patch
+Patch8: 0002-Fix-rpath-link-command-line-options.patch
+Patch9: 0003-Fix-SIMD-support-on-IBM-z13.patch
+Patch10: 0004-Read-L1-data-cache-size-from-sysconf-if-possible.patch
+Patch11: 0005-Optimizations-for-IBM-z13.patch
+Patch12: 0006-Add-IBM-z14-support.patch
+Patch13: 0007-Enable-cross-compile.patch
+Patch14: 0008-Add-IBM-z15-support.patch
+
+#Covscan
+Patch101: atlas-getri.patch
BuildRequires: gcc-gfortran, lapack-static, gcc
@@ -142,8 +152,6 @@ Linear Algebra Software).
#
%ifarch x86_64
%define types base corei2
-#corei4
-# sse3
%package corei2-static
Summary: ATLAS libraries for Corei2 (Ivy/Sandy bridge) CPUs
@@ -175,48 +183,79 @@ optimizations for the corei2 (Ivy/Sandy bridge) CPUs.
%endif
%ifarch %{ix86}
-%define types base
-#corei1
-
-#%package corei1
-#Summary: ATLAS libraries for Corei1 (Nehalem/Westmere) CPUs
-#Group: System Environment/Libraries
-
-#%description corei1
-#This package contains ATLAS (Automatically Tuned Linear Algebra Software)
-#shared libraries compiled with optimizations for the Corei1 (Nehalem/Westmere) CPUs.
-#The base ATLAS builds for the ix86 architecture are made for PIII CPUs.
-
-#%package corei1-devel
-#Summary: Development libraries for ATLAS for Corei1 (Nehalem/Westmere) CPUs
-#Group: Development/Libraries
-#Requires: %{name}-corei1 = %{version}-%{release}
-#Obsoletes: %name-header <= %version-%release
-#Requires(posttrans): /usr/sbin/alternatives
-#Requires(postun): /usr/sbin/alternatives
-
-#%description corei1-devel
-#This package contains shared and static versions of the ATLAS
-#(Automatically Tuned Linear Algebra Software) libraries compiled with
-#optimizations for the corei1 (Nehalem/Westmere) CPUs.
-
-#%package corei1-static
-#Summary: Static libraries for ATLAS for Corei1 (/Nehalem/Westmere) CPUs
-#Group: Development/Libraries
-#Requires: %{name}-corei1-devel = %{version}-%{release}
-#Requires(posttrans): /usr/sbin/alternatives
-#Requires(postun): /usr/sbin/alternatives
-
-#%description corei1-static
-#This package contains the ATLAS (Automatically Tuned Linear Algebra
-#Software) static libraries compiled with optimizations for the Corei1 (Nehalem/Westemere)
-#CPUs. The base ATLAS builds for the ix86 architecture are made for the PIII CPUs.
+%define types base
%endif
%ifarch s390 s390x
-%define types base
+%define types base z14 z15
+
+%package z14
+Summary: ATLAS libraries for z14
+Group: System Environment/Libraries
+
+%description z14
+This package contains ATLAS (Automatically Tuned Linear Algebra Software)
+shared libraries compiled with optimizations for the z14 CPUs.
+
+%package z14-devel
+Summary: Development libraries for ATLAS for z14
+Group: Development/Libraries
+Requires: %{name}-z14 = %{version}-%{release}
+Obsoletes: %name-header <= %version-%release
+Requires(posttrans): chkconfig
+Requires(postun): chkconfig
+
+%description z14-devel
+This package contains shared and static versions of the ATLAS
+(Automatically Tuned Linear Algebra Software) libraries compiled with
+optimizations for the z14 CPUs.
+
+%package z14-static
+Summary: Static libraries for ATLAS for z14
+Group: Development/Libraries
+Requires: %{name}-z14-devel = %{version}-%{release}
+Requires(posttrans): chkconfig
+Requires(postun): chkconfig
+
+%description z14-static
+This package contains the ATLAS (Automatically Tuned Linear Algebra
+Software) static libraries compiled with optimizations for the z14
+CPUs.
+
+%package z15
+Summary: ATLAS libraries for z15
+Group: System Environment/Libraries
+
+%description z15
+This package contains ATLAS (Automatically Tuned Linear Algebra Software)
+shared libraries compiled with optimizations for the z15 CPUs.
+
+%package z15-devel
+Summary: Development libraries for ATLAS for z15
+Group: Development/Libraries
+Requires: %{name}-z15 = %{version}-%{release}
+Obsoletes: %name-header <= %version-%release
+Requires(posttrans): chkconfig
+Requires(postun): chkconfig
+
+%description z15-devel
+This package contains shared and static versions of the ATLAS
+(Automatically Tuned Linear Algebra Software) libraries compiled with
+optimizations for the z15 CPUs.
+
+%package z15-static
+Summary: Static libraries for ATLAS for z15
+Group: Development/Libraries
+Requires: %{name}-z15-devel = %{version}-%{release}
+Requires(posttrans): chkconfig
+Requires(postun): chkconfig
+
+%description z15-static
+This package contains the ATLAS (Automatically Tuned Linear Algebra
+Software) static libraries compiled with optimizations for the z15
+CPUs.
%endif
@@ -292,42 +331,44 @@ CPUs. The base ATLAS builds for the ppc64 architecture are made for the Power 5
%prep
#cat /proc/cpuinfo
%setup -q -n ATLAS
-#patch0 -p0 -b .shared
-#arm patch not applicable, probably not needed
-#%ifarch %{arm}
-#%patch2 -p0 -b .arm
-#%endif
-%patch3 -p1 -b .melf
-%patch4 -p1 -b .thrott
-%patch5 -p2 -b .sharedlib
-%ifarch aarch64
-#%patch7 -p1 -b .aarch64
-%endif
-%patch8 -p1 -b .genparse
-%patch9 -p1 -b .unbundle
+
+
+%patch1 -p1
+%patch2 -p1
+%patch3 -p2
+%patch4 -p1
+%patch5 -p1
+%patch6 -p1
+
+%patch7 -p1
+%patch8 -p1
%patch10 -p1
+%ifarch s390x s390
+%patch9 -p1
+%patch11 -p1
+%patch12 -p1
+%patch13 -p1
+%patch14 -p1
+%endif
+
+%patch101 -p1
+
cp %{SOURCE1} CONFIG/ARCHS/
-#cp %{SOURCE2} CONFIG/ARCHS/
-cp %{SOURCE3} doc
+cp %{SOURCE2} doc
+cp %{SOURCE3} CONFIG/ARCHS/
+cp %{SOURCE4} CONFIG/ARCHS/
+cp %{SOURCE5} CONFIG/ARCHS/
+cp %{SOURCE6} CONFIG/ARCHS/
+cp %{SOURCE7} CONFIG/ARCHS/
+cp %{SOURCE8} CONFIG/ARCHS/
+cp %{SOURCE9} CONFIG/ARCHS/
+cp %{SOURCE10} CONFIG/ARCHS/
cp %{SOURCE11} CONFIG/ARCHS/
-cp %{SOURCE12} CONFIG/ARCHS/
-cp %{SOURCE13} CONFIG/ARCHS/
-cp %{SOURCE14} CONFIG/ARCHS/
-cp %{SOURCE15} CONFIG/ARCHS/
-cp %{SOURCE16} CONFIG/ARCHS/
-#cp %{SOURCE8} CONFIG/ARCHS/
-#cp %{SOURCE9} CONFIG/ARCHS/
%ifarch %{arm}
-# Set arm flags in atlcomp.txt
-#sed -i -e 's,-mfpu=vfpv3,-mfpu=neon,' CONFIG/src/atlcomp.txt
sed -i -e 's,-mfloat-abi=softfp,-mfloat-abi=hard,' CONFIG/src/atlcomp.txt
-# Some extra arm flags not needed
-#sed -i -e 's,-mfpu=vfpv3,,' tune/blas/gemm/CASES/*.flg
%endif
-# Debug
-#sed -i -e 's,> \(.*\)/ptsanity.out,> \1/ptsanity.out || cat \1/ptsanity.out \&\& exit 1,' makes/Make.*
# Generate lapack library
mkdir lapacklib
@@ -354,9 +395,10 @@ p=$(pwd)
%define threads_option "-t 2"
#Target architectures for the 'base' versions
-%ifarch s390x
+%ifarch s390x
%define flags %{nil}
%define base_options "-A IBMz12 -V 1"
+#%define base_options "-A IBMz13 -V 8 -Si archdef 2"
%endif
%ifarch x86_64
@@ -397,14 +439,14 @@ p=$(pwd)
%if "%{?enable_native_atlas}" != "0"
%define threads_option %{nil}
%define base_options %{nil}
-%define flags %{nil}
+%define flags %{nil}
%endif
for type in %{types}; do
if [ "$type" = "base" ]; then
libname=atlas
arg_options=%{base_options}
- thread_options=%{threads_option}
+ thread_options=%{threads_option}
%define pr_base %(echo $((%{__isa_bits}+0)))
else
libname=atlas-${type}
@@ -415,12 +457,14 @@ for type in %{types}; do
elif [ "$type" = "corei1" ]; then
arg_options="-A Corei1 -V 896"
%define pr_corei1 %(echo $((%{__isa_bits}+2)))
- elif [ "$type" = "z10" ]; then
- arg_options="-A IBMz10 -V 1"
- %define pr_z10 %(echo $((%{__isa_bits}+2)))
- elif [ "$type" = "z196" ]; then
- arg_options="-A IBMz196 -V 1"
- %define pr_z196 %(echo $((%{__isa_bits}+4)))
+ elif [ "$type" = "z14" ]; then
+ thread_options="-t 4"
+ arg_options="-A IBMz14 -V 4 -Si archdef 2"
+ %define pr_z14 %(echo $((%{__isa_bits}+2)))
+ elif [ "$type" = "z15" ]; then
+ thread_options="-t 4"
+ arg_options="-A IBMz15 -V 4 -Si archdef 2"
+ %define pr_z15 %(echo $((%{__isa_bits}+4)))
elif [ "$type" = "power7" ]; then
thread_options="-t 4"
arg_options="-A POWER7 -V 1"
@@ -433,10 +477,10 @@ for type in %{types}; do
fi
mkdir -p %{_arch}_${type}
pushd %{_arch}_${type}
- ../configure %{mode} $thread_options $arg_options -D c -DWALL -Fa alg '%{flags} -D_FORTIFY_SOURCE=2 -g -Wa,--noexecstack,--generate-missing-build-notes=yes -fstack-protector-strong -fstack-clash-protection -fPIC -fplugin=annobin -Wl,-z,now'\
+ ../configure %{mode} $thread_options $arg_options -D c -DWALL -F xc ' ' -Fa alg '%{flags} -D_FORTIFY_SOURCE=2 -g -Wa,--noexecstack,--generate-missing-build-notes=yes -fstack-protector-strong -fstack-clash-protection -fPIC -fplugin=annobin -Wl,-z,now'\
--prefix=%{buildroot}%{_prefix} \
--incdir=%{buildroot}%{_includedir} \
- --libdir=%{buildroot}%{_libdir}/${libname}
+ --libdir=%{buildroot}%{_libdir}/${libname}
#--with-netlib-lapack-tarfile=%{SOURCE10}
#matches both SLAPACK and SSLAPACK
@@ -460,7 +504,7 @@ for type in %{types}; do
popd
done
-%install
+%install
for type in %{types}; do
pushd %{_arch}_${type}
make DESTDIR=%{buildroot} install
@@ -502,9 +546,14 @@ mkdir -p %{buildroot}%{_includedir}/atlas
%check
for type in %{types}; do
- pushd %{_arch}_${type}
- make check ptcheck
- popd
+ if [ "$type" = "z14" ] || [ "$type" = "z15" ]; then
+ # skip the tests (may fail due to illegal instructions).
+ echo "Skipping tests for the $type subpackage"
+ else
+ pushd %{_arch}_${type}
+ make check ptcheck
+ popd
+ fi
done
#%endif
@@ -558,31 +607,31 @@ fi
%ifarch s390 s390x
- #%post -n atlas-z10 -p /sbin/ldconfig
+ %post -n atlas-z14 -p /sbin/ldconfig
- #%postun -n atlas-z10 -p /sbin/ldconfig
+ %postun -n atlas-z14 -p /sbin/ldconfig
- #%posttrans z10-devel
- # /usr/sbin/alternatives --install %{_includedir}/atlas atlas-inc \
- # %{_includedir}/atlas-%{_arch}-z10 %{pr_z10}
+ %posttrans z14-devel
+ /usr/sbin/alternatives --install %{_includedir}/atlas atlas-inc \
+ %{_includedir}/atlas-%{_arch}-z14 %{pr_z14}
- #%postun z10-devel
- #if [ $1 -ge 0 ] ; then
- # /usr/sbin/alternatives --remove atlas-inc %{_includedir}/atlas-%{_arch}-z10
- #fi
+ %postun z14-devel
+ if [ $1 -ge 0 ] ; then
+ /usr/sbin/alternatives --remove atlas-inc %{_includedir}/atlas-%{_arch}-z14
+ fi
- #%post -n atlas-z196 -p /sbin/ldconfig
+ %post -n atlas-z15 -p /sbin/ldconfig
- #%postun -n atlas-z196 -p /sbin/ldconfig
+ %postun -n atlas-z15 -p /sbin/ldconfig
- #%posttrans z196-devel
- # /usr/sbin/alternatives --install %{_includedir}/atlas atlas-inc \
- # %{_includedir}/atlas-%{_arch}-z196 %{pr_z196}
+ %posttrans z15-devel
+ /usr/sbin/alternatives --install %{_includedir}/atlas atlas-inc \
+ %{_includedir}/atlas-%{_arch}-z15 %{pr_z15}
- #%postun z196-devel
- #if [ $1 -ge 0 ] ; then
- # /usr/sbin/alternatives --remove atlas-inc %{_includedir}/atlas-%{_arch}-z196
- #fi
+ %postun z15-devel
+ if [ $1 -ge 0 ] ; then
+ /usr/sbin/alternatives --remove atlas-inc %{_includedir}/atlas-%{_arch}-z15
+ fi
%endif
@@ -691,11 +740,55 @@ fi
%{_libdir}/atlas-power7/*.a
%endif
+%ifarch s390 s390x
+
+%files z14
+%doc doc/README.dist
+%dir %{_libdir}/atlas-z14
+%{_libdir}/atlas-z14/*.so.*
+%config(noreplace) /etc/ld.so.conf.d/atlas-%{_arch}-z14.conf
+
+%files z14-devel
+%doc doc
+%{_libdir}/atlas-z14/*.so
+%{_includedir}/atlas-%{_arch}-z14/
+%{_includedir}/*.h
+%ghost %{_includedir}/atlas
+
+%files z14-static
+%{_libdir}/atlas-z14/*.a
+
+
+%files z15
+%doc doc/README.dist
+%dir %{_libdir}/atlas-z15
+%{_libdir}/atlas-z15/*.so.*
+%config(noreplace) /etc/ld.so.conf.d/atlas-%{_arch}-z15.conf
+
+%files z15-devel
+%doc doc
+%{_libdir}/atlas-z15/*.so
+%{_includedir}/atlas-%{_arch}-z15/
+%{_includedir}/*.h
+%ghost %{_includedir}/atlas
+
+%files z15-static
+%{_libdir}/atlas-z15/*.a
+
+%endif
+
#enable_native_atlas if
%endif
%changelog
+* Thu Aug 27 2020 Jakub Martisko <jamartis(a)redhat.com> - 3.10.3.13
+- Sync with rhel 8.3 + cleanup
+- Add new subpackages - z{14,15}
+- Unlike in rhel8, the base subpackage still needs to be build for z12.
+- Covscan related bugfixes
+- Spec and git cleanup (remove unused patches/sources)
+
* Mon Jul 27 2020 Fedora Release Engineering <releng(a)fedoraproject.org> - 3.10.3-12
- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild
diff --git a/getdoublearr.stripwhite.patch b/getdoublearr.stripwhite.patch
deleted file mode 100644
index 86358a1..0000000
--- a/getdoublearr.stripwhite.patch
+++ /dev/null
@@ -1,38 +0,0 @@
-diff -up ATLAS/include/atlas_genparse.h.than ATLAS/include/atlas_genparse.h
---- ATLAS/include/atlas_genparse.h.than 2015-11-26 10:53:55.056586198 -0500
-+++ ATLAS/include/atlas_genparse.h 2015-11-26 10:56:00.168537914 -0500
-@@ -149,13 +149,24 @@ static int asmNames2bitfield(char *str)
- }
-
- /* procedure 7 */
--static int GetDoubleArr(char *str, int N, double *d)
-+static int GetDoubleArr(char *callerstr, int N, double *d)
- /*
- * Reads in a list with form "%le,%le...,%le"; N-length d recieves doubles.
- * RETURNS: the number of doubles found, or N, whichever is less
- */
- {
-- int i=1;
-+ int i;
-+ char *dupstr = DupString(callerstr);
-+ char *str = dupstr;
-+ /* strip the string to end on first white space */
-+ for (i=0; dupstr[i]; i++)
-+ {
-+ if (isspace(dupstr[i])) {
-+ dupstr[i] = '\0';
-+ break;
-+ }
-+ }
-+ i = 1;
- assert(sscanf(str, "%le", d) == 1);
- while (i < N)
- {
-@@ -167,6 +178,7 @@ static int GetDoubleArr(char *str, int N
- break;
- i++;
- }
-+ free(dupstr);
- return(i);
- }
-
diff --git a/initialize_malloc_memory.invtrsm.wms.oct23.patch b/initialize_malloc_memory.invtrsm.wms.oct23.patch
deleted file mode 100644
index 02fa9e4..0000000
--- a/initialize_malloc_memory.invtrsm.wms.oct23.patch
+++ /dev/null
@@ -1,26 +0,0 @@
-From: Michel Normand <normand(a)linux.vnet.ibm.com>
-Subject: initialize malloc memory.invtrsm.wms.oct23
-Date: Mon, 14 Apr 2014 17:18:53 +0200
-References: http://sourceforge.net/p/math-atlas/mailman/message/32471499/
-
-initialize malloc memory invtrsm.c
-
-
-Signed-off-by: Will Schmidt <will_schmidt(a)vnet.ibm.com>
-Signed-off-by: Michel Normand <normand(a)linux.vnet.ibm.com>
----
- ATLAS/tune/blas/level3/invtrsm.c | 1 +
- 1 file changed, 1 insertion(+)
-
-Index: ATLAS/tune/blas/level3/invtrsm.c
-===================================================================
---- ATLAS.orig/tune/blas/level3/invtrsm.c
-+++ ATLAS/tune/blas/level3/invtrsm.c
-@@ -525,6 +525,7 @@ static double RunTiming
- a = A = malloc(i * ATL_MulBySize(incA));
- if (A)
- {
-+ memset(A,0,i*ATL_MulBySize(incA)); /* wms (!!) malloc call above returns non-initialized memory. */
- if (Uplo == TestGE)
- for (i=0; i < k; i++)
- Mjoin(PATL,gegen)(N, N, A+i*incA, lda, N+lda);
diff --git a/sources b/sources
index 6eed107..766db50 100644
--- a/sources
+++ b/sources
@@ -15,3 +15,6 @@ SHA512 (ARMa732.tar) = 47d6564b5a439bc3778ccc79242220b236c7dc8d36e12ce6850c7e9a0
SHA512 (ARMa732.tar.bz2) = 8b83b59a32f18d2cd432c205efd4358b0000ce1685799f2f38a60532bc925e9cd871371d2dfd226ab8e30e830bf608f022d63bcd26f26f9fe74acab067bd4d4f
SHA512 (POWER864LEVSXp4.tar.bz2) = e2fa637061a4a4806bc091009c37ccd719c4c4051baf36ed451917e255375881fa168caa5ca296ae9c89bb28523d9015fda42a5dbc51aef4c66efbf6efd966d2
SHA512 (K7323DNow.tgz) = e1d5e4208ce454b5f5daa68663d2dd28a2bd3cc97496e4e1515df880b9ccd00bcc75bd820402c3b2bf8409f98500e43f2481fbf5dd480f7d0ba60fe2f82a1ac1
+SHA512 (IBMz1364VXZ.tar.bz2) = abcd32e4e92eaee702bb9583179d7019b551c5cdc45733ef683a62627d52d002425f7eb9515c15c700160920a6cda9bdd9586a748e6bea0425958346c341481f
+SHA512 (IBMz1464VXZ2.tar.bz2) = 6783ec5658d59f8a1f1270fa9845c5aad3a320b03e7b0bee7e16c0357679118bec0bf99f0ada8815620d2df17ab10c3bd91dff2454dbd4f0e6401de69944317f
+SHA512 (IBMz1564VXZ2.tar.bz2) = ff522d80d758c508c71989a189442121e4be2f0309c7c9dcb87174bacef6a3c6caf2debc069311335a9c14930450e84a81f9be171e46f4a0c2da5ae0771a9b1c
3 years, 8 months
Architecture specific change in rpms/gdm.git
by githook-noreply@fedoraproject.org
The package rpms/gdm.git has added or updated architecture specific content in its
spec file (ExclusiveArch/ExcludeArch or %ifarch/%ifnarch) in commit(s):
https://src.fedoraproject.org/cgit/rpms/gdm.git/commit/?id=b524425e0a34e5....
Change:
-%ifnarch s390 s390x ppc ppc64
Thanks.
Full change:
============
commit b524425e0a34e5e94b2d1ac86806a624c9931c7c
Author: Dan Horák <dan(a)danny.cz>
Date: Wed May 6 03:34:41 2020 -0400
Remove stale and unnecessary architecture-specific exceptions
xorg-x11-server-Xorg is available on s390x for quite some time and the
remaining architectures aren't relevant in Fedora anymore.
https://src.fedoraproject.org/rpms/gdm/pull-request/6
diff --git a/gdm.spec b/gdm.spec
index 729a73d..16e4e2f 100644
--- a/gdm.spec
+++ b/gdm.spec
@@ -10,7 +10,7 @@
Name: gdm
Epoch: 1
Version: 3.37.90
-Release: 1%{?dist}
+Release: 2%{?dist}
Summary: The GNOME Display Manager
License: GPLv2+
@@ -52,9 +52,7 @@ BuildRequires: plymouth-devel
BuildRequires: systemd
BuildRequires: systemd-devel
BuildRequires: which
-%ifnarch s390 s390x ppc ppc64
BuildRequires: xorg-x11-server-Xorg
-%endif
BuildRequires: xorg-x11-server-devel
BuildRequires: yelp-devel
BuildRequires: yelp-tools
@@ -309,6 +307,9 @@ fi
%{_libdir}/pkgconfig/gdm-pam-extensions.pc
%changelog
+* Tue Sep 08 2020 Dan Horák <dan[at]danny.cz> - 3.37.90-2
+- Remove stale and unnecessary architecture-specific exceptions
+
* Mon Aug 17 2020 Kalev Lember <klember(a)redhat.com> - 1:3.37.90-1
- Update to 3.37.90
3 years, 8 months
Architecture specific change in rpms/gettext.git
by githook-noreply@fedoraproject.org
The package rpms/gettext.git has added or updated architecture specific content in its
spec file (ExclusiveArch/ExcludeArch or %ifarch/%ifnarch) in commit(s):
https://src.fedoraproject.org/cgit/rpms/gettext.git/commit/?id=26b1c1422c....
Change:
-%ifnarch armv7hl
Thanks.
Full change:
============
commit 26b1c1422c9c81b394cad698179548d54c197703
Author: Sundeep Anand <suanand(a)redhat.com>
Date: Mon Sep 7 18:43:16 2020 +0530
Port Gnulib test fixes from upstream
diff --git a/gettext-0.21-gnulib-perror-tests.patch b/gettext-0.21-gnulib-perror-tests.patch
new file mode 100644
index 0000000..983264d
--- /dev/null
+++ b/gettext-0.21-gnulib-perror-tests.patch
@@ -0,0 +1,44 @@
+From 175e0bc72808d564074c4adcc72aeadb74adfcc6 Mon Sep 17 00:00:00 2001
+From: Paul Eggert <eggert(a)cs.ucla.edu>
+Date: Thu, 27 Aug 2020 17:52:58 -0700
+Subject: [PATCH] perror, strerror_r: remove unportable tests
+
+Problem reported by Florian Weimer in:
+https://lists.gnu.org/r/bug-gnulib/2020-08/msg00220.html
+* tests/test-perror2.c (main):
+* tests/test-strerror_r.c (main): Omit unportable tests.
+---
+ ChangeLog | 8 ++++++++
+ tests/test-perror2.c | 3 ---
+ tests/test-strerror_r.c | 3 ---
+ 3 files changed, 8 insertions(+), 6 deletions(-)
+
+diff --git a/gettext-tools/gnulib-tests/test-perror2.c b/gettext-tools/gnulib-tests/test-perror2.c
+index 1d14eda7b..c6214dd25 100644
+--- a/gettext-tools/gnulib-tests/test-perror2.c
++++ b/gettext-tools/gnulib-tests/test-perror2.c
+@@ -79,9 +79,6 @@ main (void)
+ errno = -5;
+ perror ("");
+ ASSERT (!ferror (stderr));
+- ASSERT (msg1 == msg2 || msg1 == msg4 || STREQ (msg1, str1));
+- ASSERT (msg2 == msg4 || STREQ (msg2, str2));
+- ASSERT (msg3 == msg4 || STREQ (msg3, str3));
+ ASSERT (STREQ (msg4, str4));
+
+ free (str1);
+diff --git a/gettext-tools/gnulib-tests/test-strerror_r.c b/gettext-tools/gnulib-tests/test-strerror_r.c
+index b11d6fd9f..c1dbcf837 100644
+--- a/gettext-tools/gnulib-tests/test-strerror_r.c
++++ b/gettext-tools/gnulib-tests/test-strerror_r.c
+@@ -165,9 +165,6 @@ main (void)
+
+ strerror_r (EACCES, buf, sizeof buf);
+ strerror_r (-5, buf, sizeof buf);
+- ASSERT (msg1 == msg2 || msg1 == msg4 || STREQ (msg1, str1));
+- ASSERT (msg2 == msg4 || STREQ (msg2, str2));
+- ASSERT (msg3 == msg4 || STREQ (msg3, str3));
+ ASSERT (STREQ (msg4, str4));
+
+ free (str1);
+
diff --git a/gettext.spec b/gettext.spec
index 30b2338..935abfa 100644
--- a/gettext.spec
+++ b/gettext.spec
@@ -4,7 +4,7 @@
Summary: GNU libraries and utilities for producing multi-lingual messages
Name: gettext
Version: 0.21
-Release: 2%{?dist}
+Release: 3%{?dist}
# The following are licensed under LGPLv2+:
# - libintl and its headers
# - libasprintf and its headers
@@ -27,6 +27,9 @@ Source3: msghack.1
# this patch has merged upstream
# Patch1: gettext-msgmerge-for-msgfmt.patch
+# https://lists.gnu.org/archive/html/bug-gnulib/2020-07/msg00195.html
+Patch1: gettext-0.21-gnulib-perror-tests.patch
+
# for bootstrapping
# BuildRequires: autoconf >= 2.62
# BuildRequires: automake
@@ -287,10 +290,7 @@ cat %{name}-*.lang > %{name}.lang
export LD_LIBRARY_PATH=$RPM_BUILD_ROOT%{_libdir}:$PWD/gettext-tools/intl/.libs
# override LIBUNISTRING to prevent reordering of lib objects
-# FIXME: https://lists.gnu.org/archive/html/bug-gnulib/2020-07/msg00195.html
-%ifnarch armv7hl
make check LIBUNISTRING=-lunistring
-%endif
%ldconfig_scriptlets libs
@@ -395,6 +395,9 @@ make check LIBUNISTRING=-lunistring
%{_mandir}/man1/msghack.1*
%changelog
+* Mon Sep 7 2020 Sundeep Anand <suanand(a)redhat.com> - 0.21-3
+- include patch to fix gnulib perror tests (rhbz#1867021)
+
* Thu Aug 6 2020 Jens Petersen <petersen(a)redhat.com> - 0.21-2
- reenable testsuite except for armv7hl which is failing
3 years, 8 months
Architecture specific change in rpms/gettext.git
by githook-noreply@fedoraproject.org
The package rpms/gettext.git has added or updated architecture specific content in its
spec file (ExclusiveArch/ExcludeArch or %ifarch/%ifnarch) in commit(s):
https://src.fedoraproject.org/cgit/rpms/gettext.git/commit/?id=26b1c1422c....
Change:
-%ifnarch armv7hl
Thanks.
Full change:
============
commit 26b1c1422c9c81b394cad698179548d54c197703
Author: Sundeep Anand <suanand(a)redhat.com>
Date: Mon Sep 7 18:43:16 2020 +0530
Port Gnulib test fixes from upstream
diff --git a/gettext-0.21-gnulib-perror-tests.patch b/gettext-0.21-gnulib-perror-tests.patch
new file mode 100644
index 0000000..983264d
--- /dev/null
+++ b/gettext-0.21-gnulib-perror-tests.patch
@@ -0,0 +1,44 @@
+From 175e0bc72808d564074c4adcc72aeadb74adfcc6 Mon Sep 17 00:00:00 2001
+From: Paul Eggert <eggert(a)cs.ucla.edu>
+Date: Thu, 27 Aug 2020 17:52:58 -0700
+Subject: [PATCH] perror, strerror_r: remove unportable tests
+
+Problem reported by Florian Weimer in:
+https://lists.gnu.org/r/bug-gnulib/2020-08/msg00220.html
+* tests/test-perror2.c (main):
+* tests/test-strerror_r.c (main): Omit unportable tests.
+---
+ ChangeLog | 8 ++++++++
+ tests/test-perror2.c | 3 ---
+ tests/test-strerror_r.c | 3 ---
+ 3 files changed, 8 insertions(+), 6 deletions(-)
+
+diff --git a/gettext-tools/gnulib-tests/test-perror2.c b/gettext-tools/gnulib-tests/test-perror2.c
+index 1d14eda7b..c6214dd25 100644
+--- a/gettext-tools/gnulib-tests/test-perror2.c
++++ b/gettext-tools/gnulib-tests/test-perror2.c
+@@ -79,9 +79,6 @@ main (void)
+ errno = -5;
+ perror ("");
+ ASSERT (!ferror (stderr));
+- ASSERT (msg1 == msg2 || msg1 == msg4 || STREQ (msg1, str1));
+- ASSERT (msg2 == msg4 || STREQ (msg2, str2));
+- ASSERT (msg3 == msg4 || STREQ (msg3, str3));
+ ASSERT (STREQ (msg4, str4));
+
+ free (str1);
+diff --git a/gettext-tools/gnulib-tests/test-strerror_r.c b/gettext-tools/gnulib-tests/test-strerror_r.c
+index b11d6fd9f..c1dbcf837 100644
+--- a/gettext-tools/gnulib-tests/test-strerror_r.c
++++ b/gettext-tools/gnulib-tests/test-strerror_r.c
+@@ -165,9 +165,6 @@ main (void)
+
+ strerror_r (EACCES, buf, sizeof buf);
+ strerror_r (-5, buf, sizeof buf);
+- ASSERT (msg1 == msg2 || msg1 == msg4 || STREQ (msg1, str1));
+- ASSERT (msg2 == msg4 || STREQ (msg2, str2));
+- ASSERT (msg3 == msg4 || STREQ (msg3, str3));
+ ASSERT (STREQ (msg4, str4));
+
+ free (str1);
+
diff --git a/gettext.spec b/gettext.spec
index 30b2338..935abfa 100644
--- a/gettext.spec
+++ b/gettext.spec
@@ -4,7 +4,7 @@
Summary: GNU libraries and utilities for producing multi-lingual messages
Name: gettext
Version: 0.21
-Release: 2%{?dist}
+Release: 3%{?dist}
# The following are licensed under LGPLv2+:
# - libintl and its headers
# - libasprintf and its headers
@@ -27,6 +27,9 @@ Source3: msghack.1
# this patch has merged upstream
# Patch1: gettext-msgmerge-for-msgfmt.patch
+# https://lists.gnu.org/archive/html/bug-gnulib/2020-07/msg00195.html
+Patch1: gettext-0.21-gnulib-perror-tests.patch
+
# for bootstrapping
# BuildRequires: autoconf >= 2.62
# BuildRequires: automake
@@ -287,10 +290,7 @@ cat %{name}-*.lang > %{name}.lang
export LD_LIBRARY_PATH=$RPM_BUILD_ROOT%{_libdir}:$PWD/gettext-tools/intl/.libs
# override LIBUNISTRING to prevent reordering of lib objects
-# FIXME: https://lists.gnu.org/archive/html/bug-gnulib/2020-07/msg00195.html
-%ifnarch armv7hl
make check LIBUNISTRING=-lunistring
-%endif
%ldconfig_scriptlets libs
@@ -395,6 +395,9 @@ make check LIBUNISTRING=-lunistring
%{_mandir}/man1/msghack.1*
%changelog
+* Mon Sep 7 2020 Sundeep Anand <suanand(a)redhat.com> - 0.21-3
+- include patch to fix gnulib perror tests (rhbz#1867021)
+
* Thu Aug 6 2020 Jens Petersen <petersen(a)redhat.com> - 0.21-2
- reenable testsuite except for armv7hl which is failing
3 years, 8 months
[Report] Packages Restricting Arches
by root
New package excluding arches (8)
============================
- golang-github-howeyc-fsnotify
ExclusiveArch: %{?go_arches:%{go_arches}}%{!?go_arches:%{ix86} x86_64 %{arm}}
- nispor
ExclusiveArch: %{rust_arches}
- rust-netlink-packet-core
ExclusiveArch: %{rust_arches}
- rust-netlink-packet-route
ExclusiveArch: %{rust_arches}
- rust-netlink-packet-utils
ExclusiveArch: %{rust_arches}
- rust-netlink-proto
ExclusiveArch: %{rust_arches}
- rust-netlink-sys
ExclusiveArch: %{rust_arches}
- rust-rtnetlink
ExclusiveArch: %{rust_arches}
List of packages currently excluding arches (2510)
===========================================
- 0ad
ExclusiveArch: %{ix86} x86_64 %{arm} aarch64 ppc64le
- 90-Second-Portraits
ExclusiveArch: %{arm} %{ix86} x86_64 aarch64 ppc64le
- GoldenCheetah
ExclusiveArch: %{qt5_qtwebengine_arches}
- GtkAda
ExclusiveArch: %{GPRbuild_arches}
- GtkAda3
ExclusiveArch: %{GPRbuild_arches}
- OpenImageIO
ExclusiveArch: x86_64 ppc64le
- PragmARC
ExclusiveArch: %{GPRbuild_arches}
- R-V8
ExclusiveArch: %{nodejs_arches}
- RdRand
ExclusiveArch: %{ix86} x86_64
- RediSearch
ExclusiveArch: x86_64
- SLOF
ExclusiveArch: ppc64le
- YafaRay
ExclusiveArch: %{ix86} x86_64
- aboot
ExclusiveArch: alpha
- acpid
ExclusiveArch: ia64 x86_64 %{ix86} %{arm} aarch64
- ahven
ExclusiveArch: %{GPRbuild_arches}
- algobox
ExclusiveArch: %{qt5_qtwebengine_arches}
- alleyoop
ExclusiveArch: %{ix86} x86_64 ppc ppc64 ppc64le s390x %{arm} aarch64
- american-fuzzy-lop
ExclusiveArch: %{ix86} x86_64
- anet
ExclusiveArch: %{GPRbuild_arches}
- anki
ExclusiveArch: %{qt5_qtwebengine_arches} noarch
- apmd
ExclusiveArch: %{ix86}
- appstream-generator
ExclusiveArch: x86_64 %{ix86} %{arm}
- arduino
ExclusiveArch: %{go_arches}
- arduino-builder
ExclusiveArch: %{go_arches}
- arm-trusted-firmware
ExclusiveArch: aarch64
- aunit
ExclusiveArch: %GPRbuild_arches
- avgtime
ExclusiveArch: %{ldc_arches}
- aws
ExclusiveArch: %GPRbuild_arches
- banshee
ExclusiveArch: %{mono_arches}
- banshee-community-extensions
ExclusiveArch: %ix86 x86_64 ppc ppc64 ia64 %{arm} sparcv9 alpha s390x
- bareftp
ExclusiveArch: %{mono_arches}
- bcal
ExclusiveArch: x86_64 aarch64 ia64 ppc64 ppc64le s390x
- bcc
ExclusiveArch: x86_64 %{power64} aarch64 s390x
- bcm283x-firmware
ExclusiveArch: %{arm} aarch64
- berusky2
ExclusiveArch: %{ix86} x86_64 %{arm} aarch64 %{mips}
- biosdevname
ExclusiveArch: %{ix86} x86_64
- blender
ExclusiveArch: x86_64 aarch64 ppc64le
- bless
ExclusiveArch: %mono_arches
- boo
ExclusiveArch: %{mono_arches}
- bpftrace
ExclusiveArch: x86_64 %{power64} aarch64 s390x
- calamares
ExclusiveArch: %{ix86} x86_64
- calibre
ExclusiveArch: %{qt5_qtwebengine_arches}
- ccdciel
ExclusiveArch: %{fpc_arches}
- cdcollect
ExclusiveArch: %{mono_arches}
- ceph
ExclusiveArch: x86_64 aarch64 ppc64le s390x
- chromium
ExclusiveArch: x86_64 i686
ExclusiveArch: x86_64 i686 aarch64
- cjdns
ExclusiveArch: %{nodejs_arches}
- clevis-pin-tpm2
ExclusiveArch: %{rust_arches}
- cmospwd
ExclusiveArch: %{ix86} x86_64
- cmrt
ExclusiveArch: %{ix86} x86_64 ia64
- coffee-script
ExclusiveArch: %{nodejs_arches} noarch
- colorful
ExclusiveArch: %{fpc_arches}
- cpu-x
ExclusiveArch: i686 x86_64
- cpuid
ExclusiveArch: %{ix86} x86_64
- cqrlog
ExclusiveArch: %{fpc_arches}
- crash
ExclusiveArch: %{ix86} ia64 x86_64 ppc ppc64 s390 s390x %{arm} aarch64 ppc64le
- cri-tools
ExclusiveArch: %{?go_arches:%{go_arches}}%{!?go_arches:%{ix86} x86_64 aarch64 %{arm}}
- criu
ExclusiveArch: x86_64 %{arm} ppc64le aarch64 s390x
- cryptlib
ExclusiveArch: x86_64 %{ix86} aarch64 ppc64 ppc64le
- cryptobone
ExclusiveArch: x86_64 %{ix86} ppc64 ppc64le aarch64
- daq
ExclusiveArch: x86_64 aarch64
- darktable
ExclusiveArch: x86_64 aarch64 ppc64le
ExclusiveArch: x86_64 ppc64le
- dbus-sharp
ExclusiveArch: %mono_arches
- dbus-sharp-glib
ExclusiveArch: %mono_arches
- dbxtool
ExclusiveArch: i386 x86_64 aarch64
- deepin-daemon
ExclusiveArch: %{?go_arches:%{go_arches}}%{!?go_arches:%{ix86} x86_64 aarch64 %{arm}}
- discord-irc
ExclusiveArch: %{nodejs_arches} noarch
- dlm
ExclusiveArch: i686 x86_64
- dmidecode
ExclusiveArch: %{ix86} x86_64 ia64 aarch64
- docker-distribution
ExclusiveArch: %{?go_arches:%{go_arches}}%{!?go_arches:%{ix86} x86_64 %{arm}}
- dolphin-emu
ExclusiveArch: x86_64 aarch64
- dotnet-build-reference-packages
ExclusiveArch: aarch64 x86_64
ExclusiveArch: x86_64
- dotnet3.1
ExclusiveArch: aarch64 x86_64
ExclusiveArch: x86_64
- doublecmd
ExclusiveArch: %{ix86} x86_64
- dpdk
ExclusiveArch: x86_64 i686 aarch64 ppc64le
- dssi-vst
ExclusiveArch: %{ix86} x86_64
- dyninst
ExclusiveArch: %{ix86} x86_64 ppc64le aarch64
- e3
ExclusiveArch: %{ix86} x86_64
- edac-utils
ExclusiveArch: %{ix86} x86_64 %{arm} aarch64 %{power64}
- edb
ExclusiveArch: %{ix86} x86_64
- edk2
ExclusiveArch: %{ix86} x86_64 %{arm} aarch64
ExclusiveArch: x86_64 aarch64
- efibootmgr
ExclusiveArch: %{efi}
- efivar
ExclusiveArch: %{efi}
- elasticdump
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
ExclusiveArch: %{nodejs_arches} noarch
- elk
ExclusiveArch: x86_64 %{ix86}
ExclusiveArch: x86_64 %{ix86} aarch64 %{arm} %{power64}
- emacs-slime
ExclusiveArch: %{arm} %{ix86} x86_64 ppc sparcv9 aarch64
- embree
ExclusiveArch: x86_64 aarch64
- enki
ExclusiveArch: %{qt5_qtwebengine_arches} noarch
- envytools
ExclusiveArch: %{ix86} x86_64 %{arm} aarch64
- eric
ExclusiveArch: %{qt5_qtwebengine_arches} noarch
- extlinux-bootloader
ExclusiveArch: %{arm} aarch64
- fcitx-libpinyin
ExclusiveArch: %{qt5_qtwebengine_arches}
- fedora-dockerfiles
ExclusiveArch: %{go_arches}
- fes
ExclusiveArch: %{ix86} x86_64
- flannel
ExclusiveArch: %{ix86} x86_64 %{arm} aarch64 ppc64le s390x
- florist
ExclusiveArch: %{GPRbuild_arches}
- fpc
ExclusiveArch: %{arm} aarch64 %{ix86} x86_64 ppc64le
- frescobaldi
ExclusiveArch: %{qt5_qtwebengine_arches}
- frysk
ExclusiveArch: %{ix86} x86_64 ppc64
- fst
ExclusiveArch: i686
- fwts
ExclusiveArch: x86_64 %{arm} aarch64 s390x %{power64}
- ga
ExclusiveArch: %{ix86} x86_64 %{arm} aarch64 ppc64le
- gbrainy
ExclusiveArch: %mono_arches
- gdata-sharp
ExclusiveArch: %mono_arches
- gdb-exploitable
ExclusiveArch: x86_64 i386
ExclusiveArch: x86_64 noarch
- gearhead1
ExclusiveArch: %{fpc_arches}
- gela-asis
ExclusiveArch: %GPRbuild_arches
- ghdl
ExclusiveArch: %{GNAT_arches}
- ghostwriter
ExclusiveArch: %{qt5_qtwebengine_arches}
- gio-sharp
ExclusiveArch: %mono_arches
- gir-to-d
ExclusiveArch: %{ldc_arches}
- git-octopus
ExclusiveArch: %{?go_arches:%{go_arches}}%{!?go_arches:%{ix86} x86_64 aarch64 %{arm}}
- giver
ExclusiveArch: %{mono_arches}
- gkeyfile-sharp
ExclusiveArch: %mono_arches
- glibc32
ExclusiveArch: x86_64
- glibd
ExclusiveArch: %{ldc_arches}
- gmqcc
ExclusiveArch: %{ix86} x86_64 %{arm} aarch64
- gnatcoll
ExclusiveArch: %{GPRbuild_arches}
- gnatcoll-bindings
ExclusiveArch: %{GPRbuild_arches}
- gnatcoll-db
ExclusiveArch: %{GPRbuild_arches}
- gnome-boxes
ExclusiveArch: x86_64
- gnome-desktop-sharp
ExclusiveArch: %mono_arches
- gnome-do
ExclusiveArch: %mono_arches
- gnome-guitar
ExclusiveArch: %{mono_arches}
- gnome-keyring-sharp
ExclusiveArch: %mono_arches
- gnome-rdp
ExclusiveArch: %{mono_arches}
- gnome-sharp
ExclusiveArch: %mono_arches
- gnome-subtitles
ExclusiveArch: %mono_arches
- gnu-efi
ExclusiveArch: %{efi}
- go-bindata
ExclusiveArch: %{?go_arches:%{go_arches}}%{!?go_arches:%{ix86} x86_64 %{arm}}
- go-compilers
ExclusiveArch: %{go_arches}
- go-rpm-macros
ExclusiveArch: %{golang_arches} %{gccgo_arches}
- godep
ExclusiveArch: %{?go_arches:%{go_arches}}%{!?go_arches:%{ix86} x86_64 %{arm}}
- golang
ExclusiveArch: %{golang_arches}
- golang-github-howeyc-fsnotify
ExclusiveArch: %{?go_arches:%{go_arches}}%{!?go_arches:%{ix86} x86_64 %{arm}}
- gomtree
ExclusiveArch: %{?go_arches:%{go_arches}}%{!?go_arches:%{ix86} x86_64 %{arm}}
- gotun
ExclusiveArch: %{?go_arches:%{go_arches}}%{!?go_arches:%{ix86} x86_64 %{arm}}
ExclusiveArch: x86_64
- goverlay
ExclusiveArch: %{fpc_arches}
- gprbuild
ExclusiveArch: %{GPRbuild_arches} %{bootstrap_arch}
- gprolog
ExclusiveArch: x86_64 %{ix86} ppc alpha
- grafana
ExclusiveArch: %{grafana_arches}
- grafana-pcp
ExclusiveArch: %{nodejs_arches}
- gtk-sharp-beans
ExclusiveArch: %mono_arches
- gtk-sharp2
ExclusiveArch: %mono_arches
- gtk-sharp3
ExclusiveArch: %{mono_arches}
- gtkd
ExclusiveArch: %{ldc_arches}
- gudev-sharp
ExclusiveArch: %mono_arches
- hedgewars
ExclusiveArch: %{fpc_arches}
- hsakmt
ExclusiveArch: x86_64 aarch64
- hyena
ExclusiveArch: %{mono_arches}
- hyperscan
ExclusiveArch: x86_64
- hyperv-daemons
ExclusiveArch: i686 x86_64
- i3status-rs
ExclusiveArch: %{rust_arches}
- icaro
ExclusiveArch: %{ix86} x86_64 noarch
- imvirt
ExclusiveArch: %{ix86} x86_64 ia64
- indistarter
ExclusiveArch: %{fpc_arches}
- infinipath-psm
ExclusiveArch: x86_64
- intel-cmt-cat
ExclusiveArch: x86_64 i686 i586
ExclusiveArch: x86_64 i686 i586
- intel-gmmlib
ExclusiveArch: x86_64 i686
- intel-mediasdk
ExclusiveArch: x86_64
- intel-undervolt
ExclusiveArch: i386 x86_64
- ioport
ExclusiveArch: %{ix86} x86_64
- ipmctl
ExclusiveArch: x86_64
- ipw2100-firmware
ExclusiveArch: noarch i386 x86_64
- ipw2200-firmware
ExclusiveArch: noarch i386 x86_64
- ispc
ExclusiveArch: x86_64 aarch64
- iucode-tool
ExclusiveArch: %{ix86} x86_64
- iyfct
ExclusiveArch: %{arm} %{ix86} x86_64 aarch64 ppc64le
- java-1.8.0-openjdk-aarch32
ExclusiveArch: %{arm}
- keepass
ExclusiveArch: %{mono_arches}
- kernel
ExclusiveArch: x86_64 s390x %{arm} aarch64 ppc64le
ExclusiveArch: noarch i386 i686 x86_64 s390x %{arm} aarch64 ppc64le
- kf5-akonadi-search
ExclusiveArch: x86_64 ppc64le aarch64 %{arm}
- kf5-audiocd-kio
ExclusiveArch: x86_64 ppc64le aarch64 %{arm}
- kf5-kalarmcal
ExclusiveArch: x86_64 ppc64le aarch64 %{arm}
- kf5-kblog
ExclusiveArch: x86_64 ppc64le aarch64 %{arm}
- kf5-kcalendarcore
ExclusiveArch: x86_64 ppc64le aarch64 %{arm}
- kf5-kcalendarutils
ExclusiveArch: x86_64 ppc64le aarch64 %{arm}
- kf5-kitinerary
ExclusiveArch: x86_64 ppc64le aarch64 %{arm}
- kf5-kmailtransport
ExclusiveArch: x86_64 %{arm}
- kf5-ktnef
ExclusiveArch: x86_64 ppc64le aarch64 %{arm}
- kf5-libkdcraw
ExclusiveArch: x86_64 ppc64le %{arm}
- kicad
ExclusiveArch: %{ix86} x86_64 %{arm} aarch64 ppc64le
- kiwix-desktop
ExclusiveArch: %{qt5_qtwebengine_arches}
- knot-resolver
ExclusiveArch: %{ix86} x86_64
ExclusiveArch: %{arm} aarch64 %{ix86} x86_64
- knotes
ExclusiveArch: x86_64 %{arm}
- kompose
ExclusiveArch: %{ix86} x86_64 %{arm} aarch64 s390x
- kubernetes
ExclusiveArch: x86_64 aarch64 ppc64le s390x %{arm}
- lazarus
ExclusiveArch: %{fpc_arches}
- lazpaint
ExclusiveArch: %{fpc_arches}
- ldc
ExclusiveArch: %{ldc_arches}
- libbsr
ExclusiveArch: %{power64}
- libclc
ExclusiveArch: %{ix86} x86_64 %{arm} aarch64 %{power64} s390x
- libcxl
ExclusiveArch: %{power64}
- libdfp
ExclusiveArch: ppc ppc64 ppc64le s390 s390x x86_64
- libguestfs
ExclusiveArch: %{kernel_arches}
- libica
ExclusiveArch: s390 s390x
- libipt
ExclusiveArch: %{ix86} x86_64
ExclusiveArch: %{ix86} x86_64
- libocxl
ExclusiveArch: ppc64le
- libpmemobj-cpp
ExclusiveArch: x86_64
- libpsm2
ExclusiveArch: x86_64
- libquentier
ExclusiveArch: %{qt5_qtwebengine_arches}
- libretro-desmume2015
ExclusiveArch: i686 x86_64
- librtas
ExclusiveArch: %{power64}
- libservicelog
ExclusiveArch: ppc %{power64}
- libsmbios
ExclusiveArch: x86_64 %{ix86}
- libtaskotron
ExclusiveArch: %{kernel_arches} noarch
- libunwind
ExclusiveArch: %{arm} aarch64 hppa ia64 mips ppc %{power64} s390x %{ix86} x86_64
- libva-intel-hybrid-driver
ExclusiveArch: %{ix86} x86_64 ia64
- libvma
ExclusiveArch: x86_64 ppc64le ppc64 aarch64
- libvmi
ExclusiveArch: x86_64
- libvpd
ExclusiveArch: %{power64}
- libxsmm
ExclusiveArch: x86_64
- libzfcphbaapi
ExclusiveArch: s390 s390x
- lightdm
ExclusiveArch: x86_64 ppc64le
- log4net
ExclusiveArch: %mono_arches
- lrmi
ExclusiveArch: %{ix86}
- lsvpd
ExclusiveArch: %{power64}
- luajit
ExclusiveArch: %{arm} %{ix86} x86_64 %{mips} aarch64 s390x ppc64le
- luxcorerender
ExclusiveArch: x86_64
- mactel-boot
ExclusiveArch: x86_64
- manifest-tool
ExclusiveArch: x86_64 aarch64 ppc64le s390x
- mantle
ExclusiveArch: %{?go_arches:%{go_arches}}%{!?go_arches:%{ix86} x86_64 aarch64 %{arm}}
- marked
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- matreshka
ExclusiveArch: %GPRbuild_arches
- maxima
ExclusiveArch: %{arm} %{ix86} x86_64 aarch64 ppc sparcv9
ExclusiveArch: %{ix86} x86_64 ppc sparcv9
- mbpfan
ExclusiveArch: x86_64
- mcelog
ExclusiveArch: i686 x86_64
- mediaconch
ExclusiveArch: %{qt5_qtwebengine_arches}
- mellowplayer
ExclusiveArch: %{qt5_qtwebengine_arches}
- memkind
ExclusiveArch: x86_64
- memtest86+
ExclusiveArch: %{ix86} x86_64
- mesos
ExclusiveArch: x86_64
- microcode_ctl
ExclusiveArch: %{ix86} x86_64
- micropython
ExclusiveArch: %{arm} %{ix86} x86_64
- mine_detector
ExclusiveArch: %{GPRbuild_arches}
- minetest
ExclusiveArch: %{ix86} x86_64
ExclusiveArch: %{arm} %{ix86} x86_64 %{mips} aarch64
- mingw-wine-gecko
ExclusiveArch: %{ix86} x86_64 %{arm} aarch64
- mirrorlist-server
ExclusiveArch: %{rust_arches}
- mkbootdisk
ExclusiveArch: %{ix86} sparc sparc64 x86_64
- mocha
ExclusiveArch: %{nodejs_arches} noarch
- mod_mono
ExclusiveArch: %mono_arches
- module-build-service
ExclusiveArch: %{ix86} x86_64 noarch
- mokutil
ExclusiveArch: %{ix86} x86_64 aarch64
- mono
ExclusiveArch: %mono_arches
- mono-addins
ExclusiveArch: %mono_arches
- mono-basic
ExclusiveArch: %{mono_arches}
- mono-bouncycastle
ExclusiveArch: %mono_arches
- mono-cecil
ExclusiveArch: %mono_arches
- mono-cecil-flowanalysis
ExclusiveArch: %mono_arches
- mono-reflection
ExclusiveArch: %mono_arches
- mono-tools
ExclusiveArch: %mono_arches
- mono-zeroconf
ExclusiveArch: %mono_arches
- monobristol
ExclusiveArch: %{mono_arches}
- monodevelop
ExclusiveArch: %mono_arches
- monodevelop-debugger-gdb
ExclusiveArch: %{mono_arches}
- monosim
ExclusiveArch: %mono_arches
- mozilla-iot-gateway-addon-node
ExclusiveArch: %{nodejs_arches} noarch
- mrrescue
ExclusiveArch: %{arm} %{ix86} x86_64 aarch64 ppc64le
- msr-tools
ExclusiveArch: %{ix86} x86_64
- mustache-d
ExclusiveArch: %{ldc_arches}
- mysql-connector-net
ExclusiveArch: %{mono_arches}
- nant
ExclusiveArch: %mono_arches
- nbc
ExclusiveArch: %{fpc_arches}
- nbdkit
ExclusiveArch: x86_64
- ndesk-dbus
ExclusiveArch: %{mono_arches}
- ndesk-dbus-glib
ExclusiveArch: %{mono_arches}
- newsflash
ExclusiveArch: %{rust_arches}
- newtonsoft-json
ExclusiveArch: %{mono_arches}
- nim
ExclusiveArch: %{nim_arches}
- nispor
ExclusiveArch: %{rust_arches}
- nodejs
ExclusiveArch: %{nodejs_arches}
- nodejs-Base64
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-acorn
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-acorn-dynamic-import
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-acorn-jsx
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-acorn-object-spread
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-align-text
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-ansi-bgblack
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-ansi-bgblue
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-ansi-bgcyan
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-ansi-bggreen
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-ansi-bgmagenta
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-ansi-bgred
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-ansi-bgwhite
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-ansi-bgyellow
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-ansi-black
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-ansi-blue
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-ansi-bold
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-ansi-colors
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-ansi-cyan
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-ansi-dim
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-ansi-escapes
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-ansi-gray
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-ansi-green
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-ansi-grey
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-ansi-hidden
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-ansi-inverse
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-ansi-italic
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-ansi-magenta
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-ansi-red
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-ansi-regex
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-ansi-reset
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-ansi-strikethrough
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-ansi-styles
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-ansi-underline
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-ansi-white
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-ansi-wrap
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-ansi-yellow
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-ansicolors
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-ansistyles
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-any-path
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-any-promise
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-append-field
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-append-transform
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-are-we-there-yet
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-argparse
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-argsparser
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-arr-diff
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-arr-exclude
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-arr-flatten
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-arr-union
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-array-buffer-from-string
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-array-events
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-array-filter
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-array-find
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-array-find-index
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-array-flatten
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-array-foreach
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-array-ify
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-array-index
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-array-map
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-array-reduce
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-array-unique
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-arraybuffer-dot-slice
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-arraybuffer-equal
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-asap
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-ascli
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-asn1
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-assert-plus
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-assume
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-async
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-async-array-reduce
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-async-arrays
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-async-limiter
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-async-some
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-asynckit
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-atob
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-auto-bind
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-autoresolve
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-aws4
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-babel-code-frame
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-babel-plugin-syntax-async-functions
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-babel-plugin-syntax-async-generators
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-babylon
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-backbone
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-backoff
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-balanced-match
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-base
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-base-plugins
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-base32-encode
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-base64-url
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-base64id
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-bash-match
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-basic-auth
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-bcrypt
ExclusiveArch: %{nodejs_arches}
- nodejs-beeper
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-better-assert
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-better-than-before
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-bignumber-js
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-bind-obj-methods
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-bit-mask
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-blob
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-block-stream
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-body-parser
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-boolbase
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-boom
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-brace-expansion
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-braces
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-browser-stdout
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-bson
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-buble
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-buf-compare
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-buffer-equal
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-bufferutil
ExclusiveArch: %{nodejs_arches}
- nodejs-builtin-modules
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-builtins
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-bundle-dependencies
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-bunker
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-burrito
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-busboy
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-byline
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-cache-base
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-caching-transform
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-call-matcher
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-call-me-maybe
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-call-signature
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-callback-stream
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-caller-callsite
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-caller-path
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-callsite
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-callsites
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-camelcase
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-camelcase-keys
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-carrier
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-caseless
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-center-align
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-chai-as-promised
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-chai-json-schema
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-chai-oauth2orize-grant
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-chai-spies-next
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-chainer
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-chalk
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-char-spinner
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-character-parser
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-chardet
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-charenc
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-charm
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-check-env
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-check-error
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-ci-info
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-circular-json
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-clap
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-class-utils
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-clean-yaml-object
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-clear-require
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-cli
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-cli-color
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-cli-spinner
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-cli-table
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-cliui
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-clone-deep
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-clone-stats
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-co-mocha
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-co-with-promise
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-code-point-at
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-codemirror
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-coffee-coverage
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-collection-visit
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-color-support
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-colors
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-colour
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-columnify
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-combined-stream
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-commander
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-common-path-prefix
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-commondir
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-compare-func
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-compare-versions
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-component-indexof
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-component-inherit
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-concat-map
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-connect-livereload
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-console-group
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-consolemd
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-content-disposition
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-content-type
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-conventional-changelog-preset-loader
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-conventional-commits-filter
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-convert-hex
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-cookies
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-copy-descriptor
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-core-js
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-core-util-is
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-crc
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-cross-spawn
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-cross-spawn-async
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-crypt
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-cryptiles
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-csrf
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-css
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-css-parse
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-css-stringify
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-css-tree
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-css-what
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-csso
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-csv
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-csv-generate
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-csv-parse
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-csv-spectrum
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-csv-stringify
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-ctype
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-currently-unhandled
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-cycle
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-cyclist
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-d
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-dargs
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-data-uri-to-buffer
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-dateformat
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-death
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-debug
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-debug-fabulous
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-debug-log
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-decamelize
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-decamelize-keys
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-decimal-js
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-dedent
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-deep-is
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-deeper
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-default-require-extensions
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-defaults
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-define-property
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-delayed-stream
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-delegates
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-depd
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-deprecated
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-destroy
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-detect-file
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-detect-indent
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-detect-newline
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-detect-node
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-dezalgo
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-dicer
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-diff
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-difflib
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-dirty-chai
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-discord-js
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-docopt
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-doctrine
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-dot-prop
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-dotfile-regex
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-duplexer
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-duplexer2
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-duplexify
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-duration
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-each
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-echomd
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-ee-first
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-ejs
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-emojione
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-empty-dir
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-end-of-stream
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-error-symbol
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-es5-ext
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-es5-shim
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-es6-iterator
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-es6-promise
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-es6-promisify
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-es6-shim
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-es6-symbol
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-es6-weak-map
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-escape-html
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-escape-regexp-component
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-escape-string-regexp
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-espower-location-detector
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-espurify
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-esrecurse
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-estraverse-fb
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-estree-walker
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-event-emitter
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-events
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-events-to-array
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-everything-dot-js
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-expand-brackets
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-expand-range
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-expand-tilde
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-extend-shallow
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-extended-emitter
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-extglob
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-fancy-log
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-fast-levenshtein
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-fastfall
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-faucet
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-figures
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-file-sync-cmp
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-filename-regex
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-fill-range
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-first-chunk-stream
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-flagged-respawn
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-flush-write-stream
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-fmix
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-fn-dot-name
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-for-each
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-for-in
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-for-own
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-foreground-child
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-forever-agent
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-form-data
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-formatio
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-forwarded
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-fragment-cache
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-from
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-fs-dot-notify
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-fs-exists-cached
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-fs-exists-sync
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-fs-temp
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-fs-write-stream-atomic
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-function-loop
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-gauge
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-gaze
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-generic-pool
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-get-port
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-get-value
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-github-url-from-username-repo
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-glob
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-glob-base
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-glob-expand
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-glob-parent
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-glob-to-regexp
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-global-modules
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-global-prefix
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-globals
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-glogg
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-gonzales-pe
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-graceful-readlink
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-growl
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-grunt
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-grunt-banner
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-grunt-contrib-nodeunit
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-grunt-legacy-util
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-grunt-sed
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-grunt-simple-mocha
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-gulplog
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-has-ansi
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-has-binary
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-has-binary2
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-has-color
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-has-cors
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-has-flag
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-has-glob
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-has-gulplog
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-has-value
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-has-values
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-has-yarn
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-hawk
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-heap
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-hex-to-array-buffer
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-hoek
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-homedir-polyfill
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-hook-std
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-hosted-git-info
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-http-deceiver
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-http-signature
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-iferr
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-ignore
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-immutable
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-imul
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-imurmurhash
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-indent-string
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-indexof
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-inflight
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-info-symbol
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-int64-buffer
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-intercept-require
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-interpret
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-invert-kv
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-ipaddr-dot-js
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-irc-colors
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-irc-formatting
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-irc-upd
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-irregular-plurals
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-is-accessor-descriptor
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-is-boolean-object
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-is-buffer
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-is-builtin-module
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-is-data-descriptor
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-is-descriptor
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-is-dir
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-is-dotfile
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-is-equal-shallow
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-is-extendable
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-is-extglob
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-is-finite
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-is-fullwidth-code-point
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-is-function
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-is-generator
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-is-generator-fn
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-is-generator-function
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-is-glob
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-is-module
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-is-negated-glob
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-is-node
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-is-number
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-is-number-object
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-is-obj
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-is-observable
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-is-odd
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-is-path-cwd
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-is-path-in-cwd
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-is-path-inside
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-is-plain-obj
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-is-plain-object
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-is-primitive
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-is-promise
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-is-regexp
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-is-registered
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-is-relative
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-is-string
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-is-subset
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-is-text-path
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-is-unc-path
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-is-url
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-is-utf8
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-is-valid-glob
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-is-valid-instance
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-is-windows
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-isarray
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-isexe
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-isobject
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-isodate
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-istanbul-lib-coverage
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-istanbul-lib-hook
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-istanbul-lib-report
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-istanbul-reports
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-jade
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-jest-mock
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-js-base64
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-js-tokens
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-jschardet
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-json-stable-stringify
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-json-stringify-safe
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-json3
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-jsonfile
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-jsonify
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-jsonm
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-jsonparse
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-jsonpointer-dot-js
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-jsonselect
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-keep-alive-agent
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-keygrip
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-kind-of
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-lazy-cache
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-lcid
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-leche
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-left-pad
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-levn
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-line-numbers
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-line-reader
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-linefix
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-linkify-it
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-locate-character
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-log-driver
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-log-ok
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-log-utils
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-lolex
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-long
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-longest
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-loud-rejection
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-lru-cache
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-lru-queue
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-magic-string
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-make-error
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-makedir
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-makeerror
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-map-cache
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-map-obj
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-map-visit
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-markdown
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-markdown-it-testgen
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-matched
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-max-timeout
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-md5
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-md5-hex
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-md5-o-matic
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-mdn-data
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-mdurl
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-media-typer
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-memoize-path
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-memoizee
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-metascript
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-mime-db
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-mime-types
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-minimalistic-assert
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-minimatch
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-minimist
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-minipass
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-mixin-deep
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-mixin-object
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-mkdirp
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-modify-values
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-mongodb
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-mongodb-core
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-ms
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-multipipe
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-murmur-32
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-mustache
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-mutate-fs
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-mysql
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-mz
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-nanomsg
ExclusiveArch: %{nodejs_arches}
- nodejs-nanoseconds
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-needle
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-negative-zero
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-net-browserify-alt
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-next-tick
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-node-dot-extend
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-node-static
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-node-uuid
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-nodemon
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-nomnom
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-noncharacters
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-nopt
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-nopt-usage
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-normalize-git-url
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-normalize-path
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-npm-cache-filename
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-npm-install-checks
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-npm-package-arg
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-npm-run-path
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-nth-check
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-number-is-nan
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-oauth-sign
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-oauth2orize
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-object-copy
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-object-dot-omit
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-object-visit
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-observable-to-promise
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-obuf
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-on-finished
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-on-headers
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-once
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-open
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-option-cache
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-option-chain
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-optionator
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-options
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-optjs
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-orchestrator
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-ordered-read-streams
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-os-homedir
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-os-locale
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-os-shim
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-output-file-sync
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-own-or
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-own-or-env
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-p-finally
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-p-limit
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-p-try
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-package-license
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-packaging
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-pad
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-pad-left
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-parallel-transform
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-parse-github-repo-url
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-parse-glob
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-parse-ms
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-parse-passwd
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-parsejson
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-parseqs
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-parseuri
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-pascalcase
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-passport-http-bearer
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-path-array
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-path-dirname
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-path-is-absolute
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-path-is-inside
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-path-key
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-path-parse
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-path-to-regexp
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-path2
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-pathval
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-pbkdf2-password
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-pkginfo
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-platform
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-plur
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-posix-character-classes
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-precond
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-prelude-ls
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-preserve
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-pretty-hrtime
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-pretty-ms
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-pretty-time
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-prism-media
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-proclaim
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-progress
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-promise
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-promises-aplus-tests
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-propagate
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-propget
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-proxy-addr
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-pruddy-error
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-pseudomap
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-pump
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-pumpify
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-qs
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-qtdatastream
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-quick-lru
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-rainbowsocks
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-random-bytes
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-random-path
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-randomatic
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-raw-body
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-re-emitter
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-read-cmd-shim
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-read-file
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-readable-stream
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-readdir-enhanced
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-readdirp
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-realize-package-specifier
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-rechoir
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-regex-cache
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-regex-not
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-remove-trailing-separator
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-repeat-element
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-repeat-string
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-repeating
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-replace
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-replace-require-self
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-require-inject
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-require-main-filename
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-require-relative
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-require-uncached
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-require-yaml
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-resolve-cwd
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-resolve-dir
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-resolve-from
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-resolve-pkg
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-resolve-url
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-reusify
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-rfile
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-rhea
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-right-align
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-rimraf
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-rndm
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-rollup-plugin-buble
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-rollup-plugin-commonjs
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-rollup-plugin-json
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-rollup-plugin-node-resolve
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-rollup-plugin-typescript
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-rollup-pluginutils
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-runforcover
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-safe-buffer
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-safe-json-stringify
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-safecb
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-samsam
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-seedrandom
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-semver
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-sentiment
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-sequencify
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-serialize-error
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-server-destroy
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-set-blocking
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-set-getter
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-set-value
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-setprototypeof
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-sha
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-shallow-clone
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-shebang-command
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-shebang-regex
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-shelljs
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-sift
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-signal-exit
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-simple-asyncify
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-simple-fmt
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-simple-is
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-simple-markdown
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-sinon-chai
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-sinon-restore
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-slash
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-slide
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-snapdragon
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-snapdragon-capture
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-snapdragon-capture-set
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-snapdragon-node
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-snapdragon-util
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-snekfetch
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-sntp
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-socket-dot-io-parser
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-sorted-object
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-source-map
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-source-map-fixtures
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-source-map-resolve
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-source-map-url
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-sparkles
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-spawn-sync
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-spdx-exceptions
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-spdx-license-ids
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-spec
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-spec-js
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-split-string
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-split2
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-sprintf
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-sprintf-js
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-ssri
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-stable
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-stack-trace
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-stack-utils
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-static-extend
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-stream-consume
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-stream-each
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-stream-pair
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-stream-replace
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-stream-transform
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-streamsearch
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-streamtest
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-string
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-string-dot-prototype-dot-repeat
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-string-width
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-string_decoder
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-stringmap
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-stringscanner
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-stringset
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-strip-ansi
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-strip-bom
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-strip-bom-stream
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-strip-bom-string
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-strip-color
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-strip-eof
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-strip-json-comments
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-strip-path
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-success-symbol
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-supervisor
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-suspend
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-svgo
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-symbol-observable
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-tap-mocha-reporter
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-tap-out
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-tap-parser
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-tape
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-tapes
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-tar
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-temp-dir
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-tempfile
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-tern-liferay
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-terst
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-testdata-w3c-json-form
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-testutil
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-text-extensions
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-thenify
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-thenify-all
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-thread-sleep
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-through2-filter
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-thunkify
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-tildify
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-time-diff
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-time-stamp
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-timekeeper
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-timers-ext
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-tippex
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-tlds
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-tmatch
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-tmpl
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-to-array
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-to-object-path
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-to-regex
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-to-regex-range
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-toidentifier
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-touch
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-tracejs
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-transformers
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-traverse
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-treeify
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-tressa
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-trim
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-trim-newlines
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-trim-off-newlines
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-trivial-deferred
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-try-open
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-try-thread-sleep
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-tryor
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-tsame
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-tslib
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-tsscmp
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-tunnel-agent
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-tv4
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-tweetnacl
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-tweetnacl-util
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-type-check
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-type-is
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-type-name
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-typescript
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-uc-dot-micro
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-uid-safe
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-ultron
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-umask
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-unc-path-regex
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-underscore
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-unicode-length
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-union-value
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-unique-filename
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-unique-slug
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-unique-temp-dir
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-unpipe
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-unset-value
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-urix
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-use
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-user-home
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-utf8
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-util-extend
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-util-inspect
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-uuid
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-vali-date
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-validate-npm-package-name
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-vlq
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-vow
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-vow-queue
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-walker
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-ware
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-warning-symbol
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-watershed
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-wbuf
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-wcwidth
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-when
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-whet-dot-extend
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-win-spawn
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-window-size
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-wolfy87-eventemitter
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-woothee
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-wordwrap
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-wrap-ansi
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-wrap-fn
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-wrappy
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-write-file-atomic
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-ws
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-xdg-basedir
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-xmlhttprequest
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-y18n
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-yallist
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-yapool
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-yargs
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- nodejs-yargs-parser
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-yeast
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-yn
ExclusiveArch: %{nodejs_arches} noarch
- nodejs-zeropad
ExclusiveArch: %{nodejs_arches} noarch
- nodeunit
ExclusiveArch: %{nodejs_arches} noarch
- notify-sharp
ExclusiveArch: %{mono_arches}
- notify-sharp3
ExclusiveArch: %{mono_arches}
- nuget
ExclusiveArch: %{mono_arches}
- numatop
ExclusiveArch: x86_64 ppc64le
- nunit
ExclusiveArch: %{mono_arches}
- nunit2
ExclusiveArch: %{mono_arches}
- nvml
ExclusiveArch: x86_64 ppc64le
- nwchem
ExclusiveArch: %{ix86} x86_64 %{arm} aarch64 ppc64le
- obs-service-rust2rpm
ExclusiveArch: %{rust_arches} noarch
- oci-kvm-hook
ExclusiveArch: %{?go_arches:%{go_arches}}%{!?go_arches:%{ix86} x86_64 aarch64 %{arm}}
- oci-seccomp-bpf-hook
ExclusiveArch: x86_64 %{power64} aarch64 s390x
- oci-umount
ExclusiveArch: %{ix86} x86_64 %{arm} aarch64 ppc64le s390x %{mips}
- oidn
ExclusiveArch: x86_64
- olpc-kbdshim
ExclusiveArch: %{ix86} %{arm}
- olpc-netutils
ExclusiveArch: %{ix86} %{arm}
- olpc-utils
ExclusiveArch: %{ix86} %{arm}
- onednn
ExclusiveArch: x86_64 aarch64 ppc64le
- onedrive
ExclusiveArch: %{ldc_arches}
- opae
ExclusiveArch: x86_64
- opal-prd
ExclusiveArch: ppc64le
- open-vm-tools
ExclusiveArch: x86_64
ExclusiveArch: %{ix86} x86_64
- openblas
ExclusiveArch: %{openblas_arches}
- openjfx
ExclusiveArch: x86_64
- openjfx8
ExclusiveArch: x86_64
- openlibm
ExclusiveArch: %{arm} %{ix86} x86_64 aarch64 %{power64}
- openni
ExclusiveArch: %{ix86} x86_64 %{arm}
- openni-primesense
ExclusiveArch: %{ix86} x86_64 %{arm}
- openshadinglanguage
ExclusiveArch: x86_64 aarch64 ppc64le s390x
- openssl-ibmca
ExclusiveArch: s390 s390x
- origin
ExclusiveArch: %{go_arches}
ExclusiveArch: x86_64 aarch64 ppc64le s390x
- orion
ExclusiveArch: %{qt5_qtwebengine_arches}
- orthorobot
ExclusiveArch: %{arm} %{ix86} x86_64 aarch64 ppc64le
- paflib
ExclusiveArch: ppc %{power64}
- pcc
ExclusiveArch: %{ix86} x86_64
- pcmciautils
ExclusiveArch: %{ix86} x86_64 ia64 ppc ppc64 %{arm}
- pdfmod
ExclusiveArch: %mono_arches
- peripety
ExclusiveArch: %{rust_arches}
- perl-Dumbbench
ExclusiveArch: %{ix86} x86_64 noarch
- perl-Parse-DMIDecode
ExclusiveArch: %{ix86} x86_64 ia64 aarch64
- pesign
ExclusiveArch: %{ix86} x86_64 ia64 aarch64 %{arm}
- pesign-test-app
ExclusiveArch: x86_64
- pinta
ExclusiveArch: %mono_arches
- pioneer
ExclusiveArch: %{ix86} x86_64
- pmdk-convert
ExclusiveArch: x86_64
- pmemkv
ExclusiveArch: x86_64
- poppler-sharp
ExclusiveArch: %mono_arches
- popub
ExclusiveArch: %{?go_arches:%{go_arches}}%{!?go_arches:%{ix86} x86_64 %{arm}}
- powerpc-utils
ExclusiveArch: ppc %{power64}
- ppc64-diag
ExclusiveArch: ppc %{power64}
- psi-plus
ExclusiveArch: %{qt5_qtwebengine_arches}
- pveclib
ExclusiveArch: ppc %{power64}
- pvs-sbcl
ExclusiveArch: %{ix86} x86_64 ppc sparcv9
- pyqtwebengine
ExclusiveArch: %{qt5_qtwebengine_arches}
- python-etcd
ExclusiveArch: noarch %{ix86} x86_64 %{arm} aarch64 ppc64le s390x
- python-healpy
ExclusiveArch: aarch64 ppc64 ppc64le x86_64 s390x
- python-javabridge
ExclusiveArch: i686 x86_64
- python-openoffice
ExclusiveArch: noarch x86_64
- python-pymoc
ExclusiveArch: aarch64 ppc64 ppc64le x86_64 s390x
- python-rpi-gpio
ExclusiveArch: %{arm} aarch64
- q4wine
ExclusiveArch: %{ix86} x86_64 %{arm} aarch64
- qcint
ExclusiveArch: x86_64
- qclib
ExclusiveArch: s390 s390x
- qemu-sanity-check
ExclusiveArch: %{kernel_arches}
- qevercloud
ExclusiveArch: %{qt5_qtwebengine_arches}
- qmapshack
ExclusiveArch: %{qt5_qtwebengine_arches}
- qt4pas
ExclusiveArch: %{fpc_arches}
- qt5-qtwebengine
ExclusiveArch: %{qt5_qtwebengine_arches}
- quantum-espresso
ExclusiveArch: x86_64 %{ix86}
ExclusiveArch: x86_64 %{ix86}
- quentier
ExclusiveArch: %{qt5_qtwebengine_arches}
- rear
ExclusiveArch: %ix86 x86_64 ppc ppc64 ppc64le ia64
- redhat-lsb
ExclusiveArch: %{ix86} ia64 x86_64 ppc ppc64 s390 s390x %{arm} aarch64 ppc64le
- reg
ExclusiveArch: x86_64
- renderdoc
ExclusiveArch: %{ix86} x86_64
- reptyr
ExclusiveArch: %{ix86} x86_64 %{arm}
- rescene
ExclusiveArch: %{mono_arches}
- restsharp
ExclusiveArch: %{mono_arches}
- rhythmbox-alternative-toolbar
ExclusiveArch: %{ix86} %{arm} x86_64 ppc64 ppc64le
- rmd
ExclusiveArch: %{ix86} x86_64
- rocm-runtime
ExclusiveArch: x86_64 aarch64
- rocminfo
ExclusiveArch: x86_64 aarch64
- rpm-ostree
ExclusiveArch: %{rust_arches}
- rr
ExclusiveArch: %{ix86} x86_64
- rssguard
ExclusiveArch: %{qt5_qtwebengine_arches}
- rubygem-childprocess
ExclusiveArch: %{ix86} x86_64 noarch
- runc
ExclusiveArch: %{ix86} x86_64 %{arm} aarch64 ppc64le %{mips} s390x
- rust
ExclusiveArch: %{rust_arches}
- rust-abomonation
ExclusiveArch: %{rust_arches}
- rust-actix
ExclusiveArch: %{rust_arches}
- rust-actix-codec
ExclusiveArch: %{rust_arches}
- rust-actix-connect
ExclusiveArch: %{rust_arches}
- rust-actix-files
ExclusiveArch: %{rust_arches}
- rust-actix-http
ExclusiveArch: %{rust_arches}
- rust-actix-macros
ExclusiveArch: %{rust_arches}
- rust-actix-router
ExclusiveArch: %{rust_arches}
- rust-actix-rt
ExclusiveArch: %{rust_arches}
- rust-actix-server
ExclusiveArch: %{rust_arches}
- rust-actix-server-config
ExclusiveArch: %{rust_arches}
- rust-actix-service
ExclusiveArch: %{rust_arches}
- rust-actix-testing
ExclusiveArch: %{rust_arches}
- rust-actix-threadpool
ExclusiveArch: %{rust_arches}
- rust-actix-tls
ExclusiveArch: %{rust_arches}
- rust-actix-utils
ExclusiveArch: %{rust_arches}
- rust-actix-web
ExclusiveArch: %{rust_arches}
- rust-actix-web-codegen
ExclusiveArch: %{rust_arches}
- rust-actix_derive
ExclusiveArch: %{rust_arches}
- rust-addr2line
ExclusiveArch: %{rust_arches}
- rust-adler32
ExclusiveArch: %{rust_arches}
- rust-aes
ExclusiveArch: %{rust_arches}
- rust-aes-soft
ExclusiveArch: %{rust_arches}
- rust-afterburn
ExclusiveArch: %{rust_arches}
- rust-ahash
ExclusiveArch: %{rust_arches}
- rust-aho-corasick
ExclusiveArch: %{rust_arches}
- rust-alga
ExclusiveArch: %{rust_arches}
- rust-alga_derive
ExclusiveArch: %{rust_arches}
- rust-alloc-no-stdlib
ExclusiveArch: %{rust_arches}
- rust-alloc-stdlib
ExclusiveArch: %{rust_arches}
- rust-alphanumeric-sort
ExclusiveArch: %{rust_arches}
- rust-ammonia
ExclusiveArch: %{rust_arches}
- rust-ansi_colours
ExclusiveArch: %{rust_arches}
- rust-ansi_term
ExclusiveArch: %{rust_arches}
- rust-ansi_term0.11
ExclusiveArch: %{rust_arches}
- rust-antidote
ExclusiveArch: %{rust_arches}
- rust-anyhow
ExclusiveArch: %{rust_arches}
- rust-anymap
ExclusiveArch: %{rust_arches}
- rust-aom-sys
ExclusiveArch: %{rust_arches}
- rust-app_dirs
ExclusiveArch: %{rust_arches}
- rust-approx
ExclusiveArch: %{rust_arches}
- rust-arbitrary
ExclusiveArch: %{rust_arches}
- rust-arc-swap
ExclusiveArch: %{rust_arches}
- rust-arg_enum_proc_macro
ExclusiveArch: %{rust_arches}
- rust-argparse
ExclusiveArch: %{rust_arches}
- rust-array-init
ExclusiveArch: %{rust_arches}
- rust-arraydeque
ExclusiveArch: %{rust_arches}
- rust-arrayref
ExclusiveArch: %{rust_arches}
- rust-arrayvec
ExclusiveArch: %{rust_arches}
- rust-article_scraper
ExclusiveArch: %{rust_arches}
- rust-ascii
ExclusiveArch: %{rust_arches}
- rust-askalono
ExclusiveArch: %{rust_arches}
- rust-askalono-cli
ExclusiveArch: %{rust_arches}
- rust-askama
ExclusiveArch: %{rust_arches}
- rust-askama_derive
ExclusiveArch: %{rust_arches}
- rust-askama_escape
ExclusiveArch: %{rust_arches}
- rust-askama_shared
ExclusiveArch: %{rust_arches}
- rust-assert-json-diff
ExclusiveArch: %{rust_arches}
- rust-assert_cli
ExclusiveArch: %{rust_arches}
- rust-assert_cmd
ExclusiveArch: %{rust_arches}
- rust-assert_fs
ExclusiveArch: %{rust_arches}
- rust-assert_matches
ExclusiveArch: %{rust_arches}
- rust-async-attributes
ExclusiveArch: %{rust_arches}
- rust-async-compression
ExclusiveArch: %{rust_arches}
- rust-async-task
ExclusiveArch: %{rust_arches}
- rust-async-trait
ExclusiveArch: %{rust_arches}
- rust-asyncgit
ExclusiveArch: %{rust_arches}
- rust-atk
ExclusiveArch: %{rust_arches}
- rust-atk-sys
ExclusiveArch: %{rust_arches}
- rust-atom
ExclusiveArch: %{rust_arches}
- rust-atomicwrites
ExclusiveArch: %{rust_arches}
- rust-attohttpc
ExclusiveArch: %{rust_arches}
- rust-atty
ExclusiveArch: %{rust_arches}
- rust-autocfg
ExclusiveArch: %{rust_arches}
- rust-average
ExclusiveArch: %{rust_arches}
- rust-awc
ExclusiveArch: %{rust_arches}
- rust-backtrace
ExclusiveArch: %{rust_arches}
- rust-backtrace-sys
ExclusiveArch: %{rust_arches}
- rust-base100
ExclusiveArch: %{rust_arches}
- rust-base64
ExclusiveArch: %{rust_arches}
- rust-base64-0.10
ExclusiveArch: %{rust_arches}
- rust-base64-0.11
ExclusiveArch: %{rust_arches}
- rust-bat
ExclusiveArch: %{rust_arches}
- rust-battery
ExclusiveArch: %{rust_arches}
- rust-bencher
ExclusiveArch: %{rust_arches}
- rust-better-panic
ExclusiveArch: %{rust_arches}
- rust-bincode
ExclusiveArch: %{rust_arches}
- rust-bincode0.8
ExclusiveArch: %{rust_arches}
- rust-bindgen
ExclusiveArch: %{rust_arches}
- rust-biscuit
ExclusiveArch: %{rust_arches}
- rust-bit-set
ExclusiveArch: %{rust_arches}
- rust-bit-vec
ExclusiveArch: %{rust_arches}
- rust-bitfield
ExclusiveArch: %{rust_arches}
- rust-bitflags
ExclusiveArch: %{rust_arches}
- rust-bitmaps
ExclusiveArch: %{rust_arches}
- rust-bitstream-io
ExclusiveArch: %{rust_arches}
- rust-blake2
ExclusiveArch: %{rust_arches}
- rust-blobby
ExclusiveArch: %{rust_arches}
- rust-block-buffer
ExclusiveArch: %{rust_arches}
- rust-block-buffer0.7
ExclusiveArch: %{rust_arches}
- rust-block-cipher
ExclusiveArch: %{rust_arches}
- rust-block-cipher-trait
ExclusiveArch: %{rust_arches}
- rust-block-modes
ExclusiveArch: %{rust_arches}
- rust-block-padding
ExclusiveArch: %{rust_arches}
- rust-bodhi
ExclusiveArch: %{rust_arches}
- rust-bodhi-cli
ExclusiveArch: %{rust_arches}
- rust-box_drawing
ExclusiveArch: %{rust_arches}
- rust-brev
ExclusiveArch: %{rust_arches}
- rust-brotli
ExclusiveArch: %{rust_arches}
- rust-brotli-decompressor
ExclusiveArch: %{rust_arches}
- rust-brotli-sys
ExclusiveArch: %{rust_arches}
- rust-brotli2
ExclusiveArch: %{rust_arches}
- rust-bstr
ExclusiveArch: %{rust_arches}
- rust-buf_redux
ExclusiveArch: %{rust_arches}
- rust-bufstream
ExclusiveArch: %{rust_arches}
- rust-build_const
ExclusiveArch: %{rust_arches}
- rust-bumpalo
ExclusiveArch: %{rust_arches}
- rust-byte-tools
ExclusiveArch: %{rust_arches}
- rust-byte-unit
ExclusiveArch: %{rust_arches}
- rust-bytecount
ExclusiveArch: %{rust_arches}
- rust-bytelines
ExclusiveArch: %{rust_arches}
- rust-bytemuck
ExclusiveArch: %{rust_arches}
- rust-byteorder
ExclusiveArch: %{rust_arches}
- rust-bytes
ExclusiveArch: %{rust_arches}
- rust-bytes0.3
ExclusiveArch: %{rust_arches}
- rust-bytes0.4
ExclusiveArch: %{rust_arches}
- rust-bytesize
ExclusiveArch: %{rust_arches}
- rust-bytestring
ExclusiveArch: %{rust_arches}
- rust-bzip2
ExclusiveArch: %{rust_arches}
- rust-bzip2-sys
ExclusiveArch: %{rust_arches}
- rust-c2-chacha
ExclusiveArch: %{rust_arches}
- rust-c_vec
ExclusiveArch: %{rust_arches}
- rust-cairo-rs
ExclusiveArch: %{rust_arches}
- rust-cairo-sys-rs
ExclusiveArch: %{rust_arches}
- rust-calloop
ExclusiveArch: %{rust_arches}
- rust-caps
ExclusiveArch: %{rust_arches}
- rust-cargo
ExclusiveArch: %{rust_arches}
- rust-cargo-bloat
ExclusiveArch: %{rust_arches}
- rust-cargo-c
ExclusiveArch: %{rust_arches}
- rust-cargo-husky
ExclusiveArch: %{rust_arches}
- rust-cargo-insta
ExclusiveArch: %{rust_arches}
- rust-cargo-platform
ExclusiveArch: %{rust_arches}
- rust-cargo-readme
ExclusiveArch: %{rust_arches}
- rust-cargo_metadata
ExclusiveArch: %{rust_arches}
- rust-cassowary
ExclusiveArch: %{rust_arches}
- rust-cast
ExclusiveArch: %{rust_arches}
- rust-cbindgen
ExclusiveArch: %{rust_arches}
- rust-cc
ExclusiveArch: %{rust_arches}
- rust-cexpr
ExclusiveArch: %{rust_arches}
- rust-cfg-if
ExclusiveArch: %{rust_arches}
- rust-chainerror
ExclusiveArch: %{rust_arches}
- rust-charset
ExclusiveArch: %{rust_arches}
- rust-chbs
ExclusiveArch: %{rust_arches}
- rust-checked_int_cast
ExclusiveArch: %{rust_arches}
- rust-choosier
ExclusiveArch: %{rust_arches}
- rust-chrono
ExclusiveArch: %{rust_arches}
- rust-chrono-humanize
ExclusiveArch: %{rust_arches}
- rust-chrono-tz
ExclusiveArch: %{rust_arches}
- rust-chunked_transfer
ExclusiveArch: %{rust_arches}
- rust-clang-sys
ExclusiveArch: %{rust_arches}
- rust-clap
ExclusiveArch: %{rust_arches}
- rust-clicolors-control
ExclusiveArch: %{rust_arches}
- rust-cmake
ExclusiveArch: %{rust_arches}
- rust-color-backtrace
ExclusiveArch: %{rust_arches}
- rust-color_quant
ExclusiveArch: %{rust_arches}
- rust-colored
ExclusiveArch: %{rust_arches}
- rust-colored_json
ExclusiveArch: %{rust_arches}
- rust-compiletest_rs
ExclusiveArch: %{rust_arches}
- rust-comrak
ExclusiveArch: %{rust_arches}
- rust-config
ExclusiveArch: %{rust_arches}
- rust-console
ExclusiveArch: %{rust_arches}
- rust-console0.9
ExclusiveArch: %{rust_arches}
- rust-const-random
ExclusiveArch: %{rust_arches}
- rust-const-random-macro
ExclusiveArch: %{rust_arches}
- rust-content_inspector
ExclusiveArch: %{rust_arches}
- rust-conv
ExclusiveArch: %{rust_arches}
- rust-cookie
ExclusiveArch: %{rust_arches}
- rust-cookie_store
ExclusiveArch: %{rust_arches}
- rust-copydeps
ExclusiveArch: %{rust_arches}
- rust-copyless
ExclusiveArch: %{rust_arches}
- rust-copypasta
ExclusiveArch: %{rust_arches}
- rust-coreos-installer
ExclusiveArch: %{rust_arches}
- rust-cpio
ExclusiveArch: %{rust_arches}
- rust-cpp_demangle
ExclusiveArch: %{rust_arches}
- rust-cpuid-bool
ExclusiveArch: %{rust_arches}
- rust-crates-io
ExclusiveArch: %{rust_arches}
- rust-crc
ExclusiveArch: %{rust_arches}
- rust-crc-any
ExclusiveArch: %{rust_arches}
- rust-crc-core
ExclusiveArch: %{rust_arches}
- rust-crc32fast
ExclusiveArch: %{rust_arches}
- rust-criterion
ExclusiveArch: %{rust_arches}
- rust-criterion-plot
ExclusiveArch: %{rust_arches}
- rust-crossbeam
ExclusiveArch: %{rust_arches}
- rust-crossbeam-channel
ExclusiveArch: %{rust_arches}
- rust-crossbeam-deque
ExclusiveArch: %{rust_arches}
- rust-crossbeam-epoch
ExclusiveArch: %{rust_arches}
- rust-crossbeam-queue
ExclusiveArch: %{rust_arches}
- rust-crossbeam-utils
ExclusiveArch: %{rust_arches}
- rust-crossterm
ExclusiveArch: %{rust_arches}
- rust-crypto-hash
ExclusiveArch: %{rust_arches}
- rust-crypto-mac
ExclusiveArch: %{rust_arches}
- rust-cryptovec
ExclusiveArch: %{rust_arches}
- rust-cssparser
ExclusiveArch: %{rust_arches}
- rust-cssparser-macros
ExclusiveArch: %{rust_arches}
- rust-csv
ExclusiveArch: %{rust_arches}
- rust-csv-core
ExclusiveArch: %{rust_arches}
- rust-ctrlc
ExclusiveArch: %{rust_arches}
- rust-curl
ExclusiveArch: %{rust_arches}
- rust-curl-sys
ExclusiveArch: %{rust_arches}
- rust-custom_derive
ExclusiveArch: %{rust_arches}
- rust-darling
ExclusiveArch: %{rust_arches}
- rust-darling_core
ExclusiveArch: %{rust_arches}
- rust-darling_macro
ExclusiveArch: %{rust_arches}
- rust-dashmap
ExclusiveArch: %{rust_arches}
- rust-data-encoding
ExclusiveArch: %{rust_arches}
- rust-data-url
ExclusiveArch: %{rust_arches}
- rust-datetime
ExclusiveArch: %{rust_arches}
- rust-dav1d-sys
ExclusiveArch: %{rust_arches}
- rust-dbus
ExclusiveArch: %{rust_arches}
- rust-dbus-codegen
ExclusiveArch: %{rust_arches}
- rust-dbus-crossroads
ExclusiveArch: %{rust_arches}
- rust-dbus0.2
ExclusiveArch: %{rust_arches}
- rust-dbus0.6
ExclusiveArch: %{rust_arches}
- rust-debug-helper
ExclusiveArch: %{rust_arches}
- rust-decimal
ExclusiveArch: %{rust_arches}
- rust-deflate
ExclusiveArch: %{rust_arches}
- rust-defmac
ExclusiveArch: %{rust_arches}
- rust-delta_e
ExclusiveArch: %{rust_arches}
- rust-derivative
ExclusiveArch: %{rust_arches}
- rust-derive_arbitrary
ExclusiveArch: %{rust_arches}
- rust-derive_builder
ExclusiveArch: %{rust_arches}
- rust-derive_builder_core
ExclusiveArch: %{rust_arches}
- rust-derive_more
ExclusiveArch: %{rust_arches}
- rust-des
ExclusiveArch: %{rust_arches}
- rust-desed
ExclusiveArch: %{rust_arches}
- rust-deunicode
ExclusiveArch: %{rust_arches}
- rust-devicemapper
ExclusiveArch: %{rust_arches}
- rust-dialoguer
ExclusiveArch: %{rust_arches}
- rust-diesel
ExclusiveArch: %{rust_arches}
- rust-diesel_derives
ExclusiveArch: %{rust_arches}
- rust-diesel_migrations
ExclusiveArch: %{rust_arches}
- rust-diff
ExclusiveArch: %{rust_arches}
- rust-difference
ExclusiveArch: %{rust_arches}
- rust-digest
ExclusiveArch: %{rust_arches}
- rust-digest0.8
ExclusiveArch: %{rust_arches}
- rust-directories
ExclusiveArch: %{rust_arches}
- rust-dirs
ExclusiveArch: %{rust_arches}
- rust-dirs-sys
ExclusiveArch: %{rust_arches}
- rust-dirs2
ExclusiveArch: %{rust_arches}
- rust-diskonaut
ExclusiveArch: %{rust_arches}
- rust-dissimilar
ExclusiveArch: %{rust_arches}
- rust-dlib
ExclusiveArch: %{rust_arches}
- rust-dns-lookup
ExclusiveArch: %{rust_arches}
- rust-dns-parser
ExclusiveArch: %{rust_arches}
- rust-doc-comment
ExclusiveArch: %{rust_arches}
- rust-docmatic
ExclusiveArch: %{rust_arches}
- rust-docopt
ExclusiveArch: %{rust_arches}
- rust-dotenv
ExclusiveArch: %{rust_arches}
- rust-downcast-rs
ExclusiveArch: %{rust_arches}
- rust-dtoa
ExclusiveArch: %{rust_arches}
- rust-dtoa-short
ExclusiveArch: %{rust_arches}
- rust-dua-cli
ExclusiveArch: %{rust_arches}
- rust-duct
ExclusiveArch: %{rust_arches}
- rust-dunce
ExclusiveArch: %{rust_arches}
- rust-dutree
ExclusiveArch: %{rust_arches}
- rust-edit-distance
ExclusiveArch: %{rust_arches}
- rust-either
ExclusiveArch: %{rust_arches}
- rust-elasticlunr-rs
ExclusiveArch: %{rust_arches}
- rust-encode_unicode
ExclusiveArch: %{rust_arches}
- rust-encoding
ExclusiveArch: %{rust_arches}
- rust-encoding-index-japanese
ExclusiveArch: %{rust_arches}
- rust-encoding-index-korean
ExclusiveArch: %{rust_arches}
- rust-encoding-index-simpchinese
ExclusiveArch: %{rust_arches}
- rust-encoding-index-singlebyte
ExclusiveArch: %{rust_arches}
- rust-encoding-index-tradchinese
ExclusiveArch: %{rust_arches}
- rust-encoding_index_tests
ExclusiveArch: %{rust_arches}
- rust-encoding_rs
ExclusiveArch: %{rust_arches}
- rust-encoding_rs_io
ExclusiveArch: %{rust_arches}
- rust-entities
ExclusiveArch: %{rust_arches}
- rust-enum-as-inner
ExclusiveArch: %{rust_arches}
- rust-enum_primitive
ExclusiveArch: %{rust_arches}
- rust-enumflags2
ExclusiveArch: %{rust_arches}
- rust-enumflags2_derive
ExclusiveArch: %{rust_arches}
- rust-env_logger
ExclusiveArch: %{rust_arches}
- rust-env_logger0.4
ExclusiveArch: %{rust_arches}
- rust-env_logger0.5
ExclusiveArch: %{rust_arches}
- rust-env_logger0.6
ExclusiveArch: %{rust_arches}
- rust-environment
ExclusiveArch: %{rust_arches}
- rust-envsubst
ExclusiveArch: %{rust_arches}
- rust-erased-serde
ExclusiveArch: %{rust_arches}
- rust-err-derive
ExclusiveArch: %{rust_arches}
- rust-errln
ExclusiveArch: %{rust_arches}
- rust-errno
ExclusiveArch: %{rust_arches}
- rust-error-chain
ExclusiveArch: %{rust_arches}
- rust-escaper
ExclusiveArch: %{rust_arches}
- rust-escargot
ExclusiveArch: %{rust_arches}
- rust-euclid
ExclusiveArch: %{rust_arches}
- rust-exa
ExclusiveArch: %{rust_arches}
- rust-expat-sys
ExclusiveArch: %{rust_arches}
- rust-extend
ExclusiveArch: %{rust_arches}
- rust-extprim
ExclusiveArch: %{rust_arches}
- rust-extprim_literals_macros
ExclusiveArch: %{rust_arches}
- rust-fail
ExclusiveArch: %{rust_arches}
- rust-failure
ExclusiveArch: %{rust_arches}
- rust-failure-tools
ExclusiveArch: %{rust_arches}
- rust-failure_derive
ExclusiveArch: %{rust_arches}
- rust-fake
ExclusiveArch: %{rust_arches}
- rust-fake-simd
ExclusiveArch: %{rust_arches}
- rust-fake_clock
ExclusiveArch: %{rust_arches}
- rust-fallible-iterator
ExclusiveArch: %{rust_arches}
- rust-fastrand
ExclusiveArch: %{rust_arches}
- rust-fd-find
ExclusiveArch: %{rust_arches}
- rust-fedora
ExclusiveArch: %{rust_arches}
- rust-fedora-coreos-pinger
ExclusiveArch: %{rust_arches}
- rust-fedora-update-feedback
ExclusiveArch: %{rust_arches}
- rust-feed-rs
ExclusiveArch: %{rust_arches}
- rust-feedbin_api
ExclusiveArch: %{rust_arches}
- rust-feedly_api
ExclusiveArch: %{rust_arches}
- rust-fern
ExclusiveArch: %{rust_arches}
- rust-fever_api
ExclusiveArch: %{rust_arches}
- rust-ffsend
ExclusiveArch: %{rust_arches}
- rust-ffsend-api
ExclusiveArch: %{rust_arches}
- rust-filesize
ExclusiveArch: %{rust_arches}
- rust-filetime
ExclusiveArch: %{rust_arches}
- rust-findshlibs
ExclusiveArch: %{rust_arches}
- rust-fixedbitset
ExclusiveArch: %{rust_arches}
- rust-flame
ExclusiveArch: %{rust_arches}
- rust-flate2
ExclusiveArch: %{rust_arches}
- rust-float-cmp
ExclusiveArch: %{rust_arches}
- rust-float-ord
ExclusiveArch: %{rust_arches}
- rust-flume
ExclusiveArch: %{rust_arches}
- rust-fnv
ExclusiveArch: %{rust_arches}
- rust-foreign-types
ExclusiveArch: %{rust_arches}
- rust-foreign-types-shared
ExclusiveArch: %{rust_arches}
- rust-fragile
ExclusiveArch: %{rust_arches}
- rust-freetype-rs
ExclusiveArch: %{rust_arches}
- rust-freetype-sys
ExclusiveArch: %{rust_arches}
- rust-fs2
ExclusiveArch: %{rust_arches}
- rust-fs_extra
ExclusiveArch: %{rust_arches}
- rust-fuse
ExclusiveArch: %{rust_arches}
- rust-futf
ExclusiveArch: %{rust_arches}
- rust-futures
ExclusiveArch: %{rust_arches}
- rust-futures-channel
ExclusiveArch: %{rust_arches}
- rust-futures-core
ExclusiveArch: %{rust_arches}
- rust-futures-cpupool
ExclusiveArch: %{rust_arches}
- rust-futures-executor
ExclusiveArch: %{rust_arches}
- rust-futures-io
ExclusiveArch: %{rust_arches}
- rust-futures-macro
ExclusiveArch: %{rust_arches}
- rust-futures-sink
ExclusiveArch: %{rust_arches}
- rust-futures-task
ExclusiveArch: %{rust_arches}
- rust-futures-timer
ExclusiveArch: %{rust_arches}
- rust-futures-util
ExclusiveArch: %{rust_arches}
- rust-futures0.1
ExclusiveArch: %{rust_arches}
- rust-fuzzy-matcher
ExclusiveArch: %{rust_arches}
- rust-fxhash
ExclusiveArch: %{rust_arches}
- rust-gcsf
ExclusiveArch: %{rust_arches}
- rust-gdk
ExclusiveArch: %{rust_arches}
- rust-gdk-pixbuf
ExclusiveArch: %{rust_arches}
- rust-gdk-pixbuf-sys
ExclusiveArch: %{rust_arches}
- rust-gdk-sys
ExclusiveArch: %{rust_arches}
- rust-generic-array
ExclusiveArch: %{rust_arches}
- rust-generic-array0.12
ExclusiveArch: %{rust_arches}
- rust-getch
ExclusiveArch: %{rust_arches}
- rust-gethostname
ExclusiveArch: %{rust_arches}
- rust-getopts
ExclusiveArch: %{rust_arches}
- rust-getrandom
ExclusiveArch: %{rust_arches}
- rust-gettext-rs
ExclusiveArch: %{rust_arches}
- rust-gettext-sys
ExclusiveArch: %{rust_arches}
- rust-gif
ExclusiveArch: %{rust_arches}
- rust-gimli
ExclusiveArch: %{rust_arches}
- rust-gio
ExclusiveArch: %{rust_arches}
- rust-gio-sys
ExclusiveArch: %{rust_arches}
- rust-gir-format-check
ExclusiveArch: %{rust_arches}
- rust-git-delta
ExclusiveArch: %{rust_arches}
- rust-git2
ExclusiveArch: %{rust_arches}
- rust-git2-curl
ExclusiveArch: %{rust_arches}
- rust-gitui
ExclusiveArch: %{rust_arches}
- rust-gl_generator
ExclusiveArch: %{rust_arches}
- rust-glib
ExclusiveArch: %{rust_arches}
- rust-glib-macros
ExclusiveArch: %{rust_arches}
- rust-glib-sys
ExclusiveArch: %{rust_arches}
- rust-glob
ExclusiveArch: %{rust_arches}
- rust-globset
ExclusiveArch: %{rust_arches}
- rust-globwalk
ExclusiveArch: %{rust_arches}
- rust-glutin_egl_sys
ExclusiveArch: %{rust_arches}
- rust-glutin_glx_sys
ExclusiveArch: %{rust_arches}
- rust-gobject-sys
ExclusiveArch: %{rust_arches}
- rust-goblin
ExclusiveArch: %{rust_arches}
- rust-google-drive3-fork
ExclusiveArch: %{rust_arches}
- rust-gptman
ExclusiveArch: %{rust_arches}
- rust-grep
ExclusiveArch: %{rust_arches}
- rust-grep-cli
ExclusiveArch: %{rust_arches}
- rust-grep-matcher
ExclusiveArch: %{rust_arches}
- rust-grep-pcre2
ExclusiveArch: %{rust_arches}
- rust-grep-printer
ExclusiveArch: %{rust_arches}
- rust-grep-regex
ExclusiveArch: %{rust_arches}
- rust-grep-searcher
ExclusiveArch: %{rust_arches}
- rust-groupable
ExclusiveArch: %{rust_arches}
- rust-gspell
ExclusiveArch: %{rust_arches}
- rust-gspell-sys
ExclusiveArch: %{rust_arches}
- rust-gstreamer
ExclusiveArch: %{rust_arches}
- rust-gstreamer-audio
ExclusiveArch: %{rust_arches}
- rust-gstreamer-audio-sys
ExclusiveArch: %{rust_arches}
- rust-gstreamer-base
ExclusiveArch: %{rust_arches}
- rust-gstreamer-base-sys
ExclusiveArch: %{rust_arches}
- rust-gstreamer-editing-services
ExclusiveArch: %{rust_arches}
- rust-gstreamer-editing-services-sys
ExclusiveArch: %{rust_arches}
- rust-gstreamer-pbutils
ExclusiveArch: %{rust_arches}
- rust-gstreamer-pbutils-sys
ExclusiveArch: %{rust_arches}
- rust-gstreamer-player
ExclusiveArch: %{rust_arches}
- rust-gstreamer-player-sys
ExclusiveArch: %{rust_arches}
- rust-gstreamer-sys
ExclusiveArch: %{rust_arches}
- rust-gstreamer-video
ExclusiveArch: %{rust_arches}
- rust-gstreamer-video-sys
ExclusiveArch: %{rust_arches}
- rust-gtk
ExclusiveArch: %{rust_arches}
- rust-gtk-macros
ExclusiveArch: %{rust_arches}
- rust-gtk-rs-lgpl-docs
ExclusiveArch: %{rust_arches}
- rust-gtk-source-sys
ExclusiveArch: %{rust_arches}
- rust-gtk-sys
ExclusiveArch: %{rust_arches}
- rust-gzip-header
ExclusiveArch: %{rust_arches}
- rust-h2
ExclusiveArch: %{rust_arches}
- rust-half
ExclusiveArch: %{rust_arches}
- rust-hamcrest
ExclusiveArch: %{rust_arches}
- rust-handlebars
ExclusiveArch: %{rust_arches}
- rust-hashbrown
ExclusiveArch: %{rust_arches}
- rust-headers
ExclusiveArch: %{rust_arches}
- rust-headers-core
ExclusiveArch: %{rust_arches}
- rust-headers-derive
ExclusiveArch: %{rust_arches}
- rust-heapsize
ExclusiveArch: %{rust_arches}
- rust-heck
ExclusiveArch: %{rust_arches}
- rust-hex
ExclusiveArch: %{rust_arches}
- rust-hex-literal
ExclusiveArch: %{rust_arches}
- rust-hex-literal-impl
ExclusiveArch: %{rust_arches}
- rust-hexyl
ExclusiveArch: %{rust_arches}
- rust-hkdf
ExclusiveArch: %{rust_arches}
- rust-hmac
ExclusiveArch: %{rust_arches}
- rust-home
ExclusiveArch: %{rust_arches}
- rust-horrorshow
ExclusiveArch: %{rust_arches}
- rust-hostname
ExclusiveArch: %{rust_arches}
- rust-hostname-validator
ExclusiveArch: %{rust_arches}
- rust-html2pango
ExclusiveArch: %{rust_arches}
- rust-html5ever
ExclusiveArch: %{rust_arches}
- rust-http
ExclusiveArch: %{rust_arches}
- rust-http-body
ExclusiveArch: %{rust_arches}
- rust-http0.1
ExclusiveArch: %{rust_arches}
- rust-httparse
ExclusiveArch: %{rust_arches}
- rust-humansize
ExclusiveArch: %{rust_arches}
- rust-humantime
ExclusiveArch: %{rust_arches}
- rust-humantime1
ExclusiveArch: %{rust_arches}
- rust-hyper
ExclusiveArch: %{rust_arches}
- rust-hyper-native-tls
ExclusiveArch: %{rust_arches}
- rust-hyper-staticfile
ExclusiveArch: %{rust_arches}
- rust-hyper-tls
ExclusiveArch: %{rust_arches}
- rust-hyper0.10
ExclusiveArch: %{rust_arches}
- rust-hyperfine
ExclusiveArch: %{rust_arches}
- rust-i3ipc
ExclusiveArch: %{rust_arches}
- rust-id_tree
ExclusiveArch: %{rust_arches}
- rust-ident_case
ExclusiveArch: %{rust_arches}
- rust-idna
ExclusiveArch: %{rust_arches}
- rust-idna0.1
ExclusiveArch: %{rust_arches}
- rust-ignore
ExclusiveArch: %{rust_arches}
- rust-im-rc
ExclusiveArch: %{rust_arches}
- rust-image
ExclusiveArch: %{rust_arches}
- rust-imgref
ExclusiveArch: %{rust_arches}
- rust-indexmap
ExclusiveArch: %{rust_arches}
- rust-indicatif
ExclusiveArch: %{rust_arches}
- rust-inflate
ExclusiveArch: %{rust_arches}
- rust-inotify
ExclusiveArch: %{rust_arches}
- rust-inotify-sys
ExclusiveArch: %{rust_arches}
- rust-input_buffer
ExclusiveArch: %{rust_arches}
- rust-insta
ExclusiveArch: %{rust_arches}
- rust-instant
ExclusiveArch: %{rust_arches}
- rust-interpolate_name
ExclusiveArch: %{rust_arches}
- rust-intervaltree
ExclusiveArch: %{rust_arches}
- rust-invalidstring
ExclusiveArch: %{rust_arches}
- rust-iovec
ExclusiveArch: %{rust_arches}
- rust-ipnet
ExclusiveArch: %{rust_arches}
- rust-ipnetwork
ExclusiveArch: %{rust_arches}
- rust-iron
ExclusiveArch: %{rust_arches}
- rust-isahc
ExclusiveArch: %{rust_arches}
- rust-iso8601
ExclusiveArch: %{rust_arches}
- rust-iter-read
ExclusiveArch: %{rust_arches}
- rust-itertools
ExclusiveArch: %{rust_arches}
- rust-itertools-num
ExclusiveArch: %{rust_arches}
- rust-itertools0.8
ExclusiveArch: %{rust_arches}
- rust-itoa
ExclusiveArch: %{rust_arches}
- rust-ivf
ExclusiveArch: %{rust_arches}
- rust-javascriptcore-rs
ExclusiveArch: %{rust_arches}
- rust-javascriptcore-rs-sys
ExclusiveArch: %{rust_arches}
- rust-jetscii
ExclusiveArch: %{rust_arches}
- rust-jobserver
ExclusiveArch: %{rust_arches}
- rust-jpeg-decoder
ExclusiveArch: %{rust_arches}
- rust-jql
ExclusiveArch: %{rust_arches}
- rust-js-sys
ExclusiveArch: %{rust_arches}
- rust-json
ExclusiveArch: %{rust_arches}
- rust-jwalk
ExclusiveArch: %{rust_arches}
- rust-keccak
ExclusiveArch: %{rust_arches}
- rust-khronos_api
ExclusiveArch: %{rust_arches}
- rust-kstring
ExclusiveArch: %{rust_arches}
- rust-kv-log-macro
ExclusiveArch: %{rust_arches}
- rust-lab
ExclusiveArch: %{rust_arches}
- rust-language-tags
ExclusiveArch: %{rust_arches}
- rust-lazy-init
ExclusiveArch: %{rust_arches}
- rust-lazy_static
ExclusiveArch: %{rust_arches}
- rust-lazycell
ExclusiveArch: %{rust_arches}
- rust-letter-avatar
ExclusiveArch: %{rust_arches}
- rust-lexical-core
ExclusiveArch: %{rust_arches}
- rust-libc
ExclusiveArch: %{rust_arches}
- rust-libcryptsetup-rs
ExclusiveArch: %{rust_arches}
- rust-libcryptsetup-rs-sys
ExclusiveArch: %{rust_arches}
- rust-libdbus-sys
ExclusiveArch: %{rust_arches}
- rust-libflate
ExclusiveArch: %{rust_arches}
- rust-libflate_lz77
ExclusiveArch: %{rust_arches}
- rust-libgit2-sys
ExclusiveArch: %{rust_arches}
- rust-libhandy
ExclusiveArch: %{rust_arches}
- rust-libhandy-sys
ExclusiveArch: %{rust_arches}
- rust-libloading
ExclusiveArch: %{rust_arches}
- rust-libm
ExclusiveArch: %{rust_arches}
- rust-libmount
ExclusiveArch: %{rust_arches}
- rust-liboverdrop
ExclusiveArch: %{rust_arches}
- rust-libpulse-binding
ExclusiveArch: %{rust_arches}
- rust-libpulse-sys
ExclusiveArch: %{rust_arches}
- rust-libslirp
ExclusiveArch: %{rust_arches}
- rust-libslirp-sys
ExclusiveArch: %{rust_arches}
- rust-libsqlite3-sys
ExclusiveArch: %{rust_arches}
- rust-libssh2-sys
ExclusiveArch: %{rust_arches}
- rust-libsystemd
ExclusiveArch: %{rust_arches}
- rust-libudev
ExclusiveArch: %{rust_arches}
- rust-libudev-sys
ExclusiveArch: %{rust_arches}
- rust-libxml
ExclusiveArch: %{rust_arches}
- rust-libz-sys
ExclusiveArch: %{rust_arches}
- rust-line-wrap
ExclusiveArch: %{rust_arches}
- rust-linked-hash-map
ExclusiveArch: %{rust_arches}
- rust-linkify
ExclusiveArch: %{rust_arches}
- rust-lipsum
ExclusiveArch: %{rust_arches}
- rust-liquid
ExclusiveArch: %{rust_arches}
- rust-liquid-core
ExclusiveArch: %{rust_arches}
- rust-liquid-derive
ExclusiveArch: %{rust_arches}
- rust-liquid-lib
ExclusiveArch: %{rust_arches}
- rust-listenfd
ExclusiveArch: %{rust_arches}
- rust-lmdb
ExclusiveArch: %{rust_arches}
- rust-lmdb-sys
ExclusiveArch: %{rust_arches}
- rust-locale
ExclusiveArch: %{rust_arches}
- rust-locale_config
ExclusiveArch: %{rust_arches}
- rust-lock_api
ExclusiveArch: %{rust_arches}
- rust-lockfree
ExclusiveArch: %{rust_arches}
- rust-log
ExclusiveArch: %{rust_arches}
- rust-log-mdc
ExclusiveArch: %{rust_arches}
- rust-log-panics
ExclusiveArch: %{rust_arches}
- rust-log0.3
ExclusiveArch: %{rust_arches}
- rust-log4rs
ExclusiveArch: %{rust_arches}
- rust-loggerv
ExclusiveArch: %{rust_arches}
- rust-loopdev
ExclusiveArch: %{rust_arches}
- rust-lru-cache
ExclusiveArch: %{rust_arches}
- rust-lru_time_cache
ExclusiveArch: %{rust_arches}
- rust-lscolors
ExclusiveArch: %{rust_arches}
- rust-lsd
ExclusiveArch: %{rust_arches}
- rust-lzma-sys
ExclusiveArch: %{rust_arches}
- rust-lzw
ExclusiveArch: %{rust_arches}
- rust-mac
ExclusiveArch: %{rust_arches}
- rust-macro-attr
ExclusiveArch: %{rust_arches}
- rust-magic-crypt
ExclusiveArch: %{rust_arches}
- rust-maildir
ExclusiveArch: %{rust_arches}
- rust-mailparse
ExclusiveArch: %{rust_arches}
- rust-man
ExclusiveArch: %{rust_arches}
- rust-maplit
ExclusiveArch: %{rust_arches}
- rust-markup5ever
ExclusiveArch: %{rust_arches}
- rust-markup5ever_rcdom
ExclusiveArch: %{rust_arches}
- rust-match_cfg
ExclusiveArch: %{rust_arches}
- rust-matches
ExclusiveArch: %{rust_arches}
- rust-matrixmultiply
ExclusiveArch: %{rust_arches}
- rust-maxminddb
ExclusiveArch: %{rust_arches}
- rust-maybe-uninit
ExclusiveArch: %{rust_arches}
- rust-mbox
ExclusiveArch: %{rust_arches}
- rust-md-5
ExclusiveArch: %{rust_arches}
- rust-md5
ExclusiveArch: %{rust_arches}
- rust-mdl
ExclusiveArch: %{rust_arches}
- rust-memchr
ExclusiveArch: %{rust_arches}
- rust-memmap
ExclusiveArch: %{rust_arches}
- rust-memmap2
ExclusiveArch: %{rust_arches}
- rust-memoffset
ExclusiveArch: %{rust_arches}
- rust-metadeps
ExclusiveArch: %{rust_arches}
- rust-migrations_internals
ExclusiveArch: %{rust_arches}
- rust-migrations_macros
ExclusiveArch: %{rust_arches}
- rust-mime
ExclusiveArch: %{rust_arches}
- rust-mime-sniffer
ExclusiveArch: %{rust_arches}
- rust-mime0.2
ExclusiveArch: %{rust_arches}
- rust-mime_guess
ExclusiveArch: %{rust_arches}
- rust-mime_guess1
ExclusiveArch: %{rust_arches}
- rust-miniflux_api
ExclusiveArch: %{rust_arches}
- rust-miniz-sys
ExclusiveArch: %{rust_arches}
- rust-miniz_oxide
ExclusiveArch: %{rust_arches}
- rust-miniz_oxide_c_api
ExclusiveArch: %{rust_arches}
- rust-mint
ExclusiveArch: %{rust_arches}
- rust-mio
ExclusiveArch: %{rust_arches}
- rust-mio-extras
ExclusiveArch: %{rust_arches}
- rust-mio-uds
ExclusiveArch: %{rust_arches}
- rust-mio0.6
ExclusiveArch: %{rust_arches}
- rust-mktemp
ExclusiveArch: %{rust_arches}
- rust-mnt
ExclusiveArch: %{rust_arches}
- rust-mockito
ExclusiveArch: %{rust_arches}
- rust-modifier
ExclusiveArch: %{rust_arches}
- rust-muldiv
ExclusiveArch: %{rust_arches}
- rust-multimap
ExclusiveArch: %{rust_arches}
- rust-multipart
ExclusiveArch: %{rust_arches}
- rust-mustache
ExclusiveArch: %{rust_arches}
- rust-nalgebra
ExclusiveArch: %{rust_arches}
- rust-nasm-rs
ExclusiveArch: %{rust_arches}
- rust-native-tls
ExclusiveArch: %{rust_arches}
- rust-natord
ExclusiveArch: %{rust_arches}
- rust-net2
ExclusiveArch: %{rust_arches}
- rust-netlink-packet-core
ExclusiveArch: %{rust_arches}
- rust-netlink-packet-route
ExclusiveArch: %{rust_arches}
- rust-netlink-packet-utils
ExclusiveArch: %{rust_arches}
- rust-netlink-proto
ExclusiveArch: %{rust_arches}
- rust-netlink-sys
ExclusiveArch: %{rust_arches}
- rust-netmap_sys
ExclusiveArch: %{rust_arches}
- rust-new_debug_unreachable
ExclusiveArch: %{rust_arches}
- rust-news-flash
ExclusiveArch: %{rust_arches}
- rust-newtype_derive
ExclusiveArch: %{rust_arches}
- rust-nickel
ExclusiveArch: %{rust_arches}
- rust-nix
ExclusiveArch: %{rust_arches}
- rust-nix0.14
ExclusiveArch: %{rust_arches}
- rust-no-panic
ExclusiveArch: %{rust_arches}
- rust-nodrop
ExclusiveArch: %{rust_arches}
- rust-nom
ExclusiveArch: %{rust_arches}
- rust-nom4
ExclusiveArch: %{rust_arches}
- rust-noop_proc_macro
ExclusiveArch: %{rust_arches}
- rust-normalize-line-endings
ExclusiveArch: %{rust_arches}
- rust-notify
ExclusiveArch: %{rust_arches}
- rust-num
ExclusiveArch: %{rust_arches}
- rust-num-bigint
ExclusiveArch: %{rust_arches}
- rust-num-bigint-dig
ExclusiveArch: %{rust_arches}
- rust-num-complex
ExclusiveArch: %{rust_arches}
- rust-num-derive
ExclusiveArch: %{rust_arches}
- rust-num-integer
ExclusiveArch: %{rust_arches}
- rust-num-iter
ExclusiveArch: %{rust_arches}
- rust-num-rational
ExclusiveArch: %{rust_arches}
- rust-num-traits
ExclusiveArch: %{rust_arches}
- rust-num-traits0.1
ExclusiveArch: %{rust_arches}
- rust-num_cpus
ExclusiveArch: %{rust_arches}
- rust-number_prefix
ExclusiveArch: %{rust_arches}
- rust-numtoa
ExclusiveArch: %{rust_arches}
- rust-obfstr
ExclusiveArch: %{rust_arches}
- rust-obfstr-impl
ExclusiveArch: %{rust_arches}
- rust-object
ExclusiveArch: %{rust_arches}
- rust-odds
ExclusiveArch: %{rust_arches}
- rust-once_cell
ExclusiveArch: %{rust_arches}
- rust-onig
ExclusiveArch: %{rust_arches}
- rust-onig_sys
ExclusiveArch: %{rust_arches}
- rust-oorandom
ExclusiveArch: %{rust_arches}
- rust-opaque-debug
ExclusiveArch: %{rust_arches}
- rust-open
ExclusiveArch: %{rust_arches}
- rust-openat
ExclusiveArch: %{rust_arches}
- rust-opener
ExclusiveArch: %{rust_arches}
- rust-openssh-keys
ExclusiveArch: %{rust_arches}
- rust-openssl
ExclusiveArch: %{rust_arches}
- rust-openssl-probe
ExclusiveArch: %{rust_arches}
- rust-openssl-sys
ExclusiveArch: %{rust_arches}
- rust-ord_subset
ExclusiveArch: %{rust_arches}
- rust-ordered-float
ExclusiveArch: %{rust_arches}
- rust-os_info
ExclusiveArch: %{rust_arches}
- rust-os_pipe
ExclusiveArch: %{rust_arches}
- rust-osmesa-sys
ExclusiveArch: %{rust_arches}
- rust-osstrtools
ExclusiveArch: %{rust_arches}
- rust-ostree
ExclusiveArch: %{rust_arches}
- rust-ostree-sys
ExclusiveArch: %{rust_arches}
- rust-owned-alloc
ExclusiveArch: %{rust_arches}
- rust-owning_ref
ExclusiveArch: %{rust_arches}
- rust-packaging
ExclusiveArch: %{rust_arches}
- rust-pad
ExclusiveArch: %{rust_arches}
- rust-pager
ExclusiveArch: %{rust_arches}
- rust-pango
ExclusiveArch: %{rust_arches}
- rust-pango-sys
ExclusiveArch: %{rust_arches}
- rust-pangocairo
ExclusiveArch: %{rust_arches}
- rust-pangocairo-sys
ExclusiveArch: %{rust_arches}
- rust-parity-wasm
ExclusiveArch: %{rust_arches}
- rust-parking_lot
ExclusiveArch: %{rust_arches}
- rust-parking_lot_core
ExclusiveArch: %{rust_arches}
- rust-parse-zoneinfo
ExclusiveArch: %{rust_arches}
- rust-partial-io
ExclusiveArch: %{rust_arches}
- rust-paste
ExclusiveArch: %{rust_arches}
- rust-paste-impl
ExclusiveArch: %{rust_arches}
- rust-path-absolutize
ExclusiveArch: %{rust_arches}
- rust-path-dedot
ExclusiveArch: %{rust_arches}
- rust-path-slash
ExclusiveArch: %{rust_arches}
- rust-pathdiff
ExclusiveArch: %{rust_arches}
- rust-pbr
ExclusiveArch: %{rust_arches}
- rust-pcap
ExclusiveArch: %{rust_arches}
- rust-pcre2
ExclusiveArch: %{rust_arches}
- rust-pcre2-sys
ExclusiveArch: %{rust_arches}
- rust-peeking_take_while
ExclusiveArch: %{rust_arches}
- rust-peg
ExclusiveArch: %{rust_arches}
- rust-pem
ExclusiveArch: %{rust_arches}
- rust-percent-encoding
ExclusiveArch: %{rust_arches}
- rust-percent-encoding1
ExclusiveArch: %{rust_arches}
- rust-peresil
ExclusiveArch: %{rust_arches}
- rust-permutate
ExclusiveArch: %{rust_arches}
- rust-permutohedron
ExclusiveArch: %{rust_arches}
- rust-pest
ExclusiveArch: %{rust_arches}
- rust-pest_derive
ExclusiveArch: %{rust_arches}
- rust-pest_generator
ExclusiveArch: %{rust_arches}
- rust-pest_meta
ExclusiveArch: %{rust_arches}
- rust-petgraph
ExclusiveArch: %{rust_arches}
- rust-phf
ExclusiveArch: %{rust_arches}
- rust-phf0.7
ExclusiveArch: %{rust_arches}
- rust-phf_codegen
ExclusiveArch: %{rust_arches}
- rust-phf_codegen0.7
ExclusiveArch: %{rust_arches}
- rust-phf_generator
ExclusiveArch: %{rust_arches}
- rust-phf_generator0.7
ExclusiveArch: %{rust_arches}
- rust-phf_macros
ExclusiveArch: %{rust_arches}
- rust-phf_macros0.7
ExclusiveArch: %{rust_arches}
- rust-phf_shared
ExclusiveArch: %{rust_arches}
- rust-phf_shared0.7
ExclusiveArch: %{rust_arches}
- rust-pico-args
ExclusiveArch: %{rust_arches}
- rust-pin-project
ExclusiveArch: %{rust_arches}
- rust-pin-project-internal
ExclusiveArch: %{rust_arches}
- rust-pin-project-lite
ExclusiveArch: %{rust_arches}
- rust-pin-utils
ExclusiveArch: %{rust_arches}
- rust-pipe
ExclusiveArch: %{rust_arches}
- rust-piper
ExclusiveArch: %{rust_arches}
- rust-pkg-config
ExclusiveArch: %{rust_arches}
- rust-plain
ExclusiveArch: %{rust_arches}
- rust-platform-dirs
ExclusiveArch: %{rust_arches}
- rust-platforms
ExclusiveArch: %{rust_arches}
- rust-plist
ExclusiveArch: %{rust_arches}
- rust-plugin
ExclusiveArch: %{rust_arches}
- rust-pnet_base
ExclusiveArch: %{rust_arches}
- rust-pnet_datalink
ExclusiveArch: %{rust_arches}
- rust-pnet_sys
ExclusiveArch: %{rust_arches}
- rust-png
ExclusiveArch: %{rust_arches}
- rust-podio
ExclusiveArch: %{rust_arches}
- rust-pommes
ExclusiveArch: %{rust_arches}
- rust-ppv-lite86
ExclusiveArch: %{rust_arches}
- rust-pq-sys
ExclusiveArch: %{rust_arches}
- rust-precomputed-hash
ExclusiveArch: %{rust_arches}
- rust-predicates
ExclusiveArch: %{rust_arches}
- rust-predicates-core
ExclusiveArch: %{rust_arches}
- rust-predicates-tree
ExclusiveArch: %{rust_arches}
- rust-pretty-git-prompt
ExclusiveArch: %{rust_arches}
- rust-pretty-hex
ExclusiveArch: %{rust_arches}
- rust-pretty_assertions
ExclusiveArch: %{rust_arches}
- rust-pretty_env_logger
ExclusiveArch: %{rust_arches}
- rust-prettytable-rs
ExclusiveArch: %{rust_arches}
- rust-proc-macro-crate
ExclusiveArch: %{rust_arches}
- rust-proc-macro-error
ExclusiveArch: %{rust_arches}
- rust-proc-macro-error-attr
ExclusiveArch: %{rust_arches}
- rust-proc-macro-hack
ExclusiveArch: %{rust_arches}
- rust-proc-macro-nested
ExclusiveArch: %{rust_arches}
- rust-proc-macro2
ExclusiveArch: %{rust_arches}
- rust-proc-macro2-0.4
ExclusiveArch: %{rust_arches}
- rust-proc-quote
ExclusiveArch: %{rust_arches}
- rust-proc-quote-impl
ExclusiveArch: %{rust_arches}
- rust-procedural-masquerade
ExclusiveArch: %{rust_arches}
- rust-process_path
ExclusiveArch: %{rust_arches}
- rust-procfs
ExclusiveArch: %{rust_arches}
- rust-procs
ExclusiveArch: %{rust_arches}
- rust-progress-streams
ExclusiveArch: %{rust_arches}
- rust-prometheus
ExclusiveArch: %{rust_arches}
- rust-proptest
ExclusiveArch: %{rust_arches}
- rust-proptest-derive
ExclusiveArch: %{rust_arches}
- rust-prost
ExclusiveArch: %{rust_arches}
- rust-prost-derive
ExclusiveArch: %{rust_arches}
- rust-prost-types
ExclusiveArch: %{rust_arches}
- rust-protobuf
ExclusiveArch: %{rust_arches}
- rust-protobuf-codegen
ExclusiveArch: %{rust_arches}
- rust-protobuf-codegen-pure
ExclusiveArch: %{rust_arches}
- rust-protoc
ExclusiveArch: %{rust_arches}
- rust-protoc-rust
ExclusiveArch: %{rust_arches}
- rust-psa-crypto
ExclusiveArch: %{rust_arches}
- rust-psa-crypto-sys
ExclusiveArch: %{rust_arches}
- rust-psm
ExclusiveArch: %{rust_arches}
- rust-psutil
ExclusiveArch: %{rust_arches}
- rust-publicsuffix
ExclusiveArch: %{rust_arches}
- rust-pulldown-cmark
ExclusiveArch: %{rust_arches}
- rust-pulse
ExclusiveArch: %{rust_arches}
- rust-qr2term
ExclusiveArch: %{rust_arches}
- rust-qrcode
ExclusiveArch: %{rust_arches}
- rust-quick-error
ExclusiveArch: %{rust_arches}
- rust-quickcheck
ExclusiveArch: %{rust_arches}
- rust-quickcheck0.6
ExclusiveArch: %{rust_arches}
- rust-quickcheck_macros
ExclusiveArch: %{rust_arches}
- rust-quickersort
ExclusiveArch: %{rust_arches}
- rust-quote
ExclusiveArch: %{rust_arches}
- rust-quote0.3
ExclusiveArch: %{rust_arches}
- rust-quote0.6
ExclusiveArch: %{rust_arches}
- rust-quoted_printable
ExclusiveArch: %{rust_arches}
- rust-r2d2
ExclusiveArch: %{rust_arches}
- rust-rand
ExclusiveArch: %{rust_arches}
- rust-rand0.4
ExclusiveArch: %{rust_arches}
- rust-rand0.5
ExclusiveArch: %{rust_arches}
- rust-rand0.6
ExclusiveArch: %{rust_arches}
- rust-rand_chacha
ExclusiveArch: %{rust_arches}
- rust-rand_chacha0.1
ExclusiveArch: %{rust_arches}
- rust-rand_core
ExclusiveArch: %{rust_arches}
- rust-rand_core0.3
ExclusiveArch: %{rust_arches}
- rust-rand_core0.4
ExclusiveArch: %{rust_arches}
- rust-rand_distr
ExclusiveArch: %{rust_arches}
- rust-rand_hc
ExclusiveArch: %{rust_arches}
- rust-rand_hc0.1
ExclusiveArch: %{rust_arches}
- rust-rand_isaac
ExclusiveArch: %{rust_arches}
- rust-rand_isaac0.1
ExclusiveArch: %{rust_arches}
- rust-rand_jitter
ExclusiveArch: %{rust_arches}
- rust-rand_jitter0.1
ExclusiveArch: %{rust_arches}
- rust-rand_os
ExclusiveArch: %{rust_arches}
- rust-rand_os0.1
ExclusiveArch: %{rust_arches}
- rust-rand_pcg
ExclusiveArch: %{rust_arches}
- rust-rand_pcg0.1
ExclusiveArch: %{rust_arches}
- rust-rand_xorshift
ExclusiveArch: %{rust_arches}
- rust-rand_xorshift0.1
ExclusiveArch: %{rust_arches}
- rust-rand_xoshiro
ExclusiveArch: %{rust_arches}
- rust-random-fast-rng
ExclusiveArch: %{rust_arches}
- rust-random-trait
ExclusiveArch: %{rust_arches}
- rust-randomize
ExclusiveArch: %{rust_arches}
- rust-rav1e
ExclusiveArch: %{rust_arches}
- rust-raw-window-handle
ExclusiveArch: %{rust_arches}
- rust-rawpointer
ExclusiveArch: %{rust_arches}
- rust-rawslice
ExclusiveArch: %{rust_arches}
- rust-rayon
ExclusiveArch: %{rust_arches}
- rust-rayon-core
ExclusiveArch: %{rust_arches}
- rust-readwrite
ExclusiveArch: %{rust_arches}
- rust-recycler
ExclusiveArch: %{rust_arches}
- rust-ref-cast
ExclusiveArch: %{rust_arches}
- rust-ref-cast-impl
ExclusiveArch: %{rust_arches}
- rust-regex
ExclusiveArch: %{rust_arches}
- rust-regex-automata
ExclusiveArch: %{rust_arches}
- rust-regex-syntax
ExclusiveArch: %{rust_arches}
- rust-region
ExclusiveArch: %{rust_arches}
- rust-relay
ExclusiveArch: %{rust_arches}
- rust-remove_dir_all
ExclusiveArch: %{rust_arches}
- rust-reqwest
ExclusiveArch: %{rust_arches}
- rust-resize
ExclusiveArch: %{rust_arches}
- rust-resolv-conf
ExclusiveArch: %{rust_arches}
- rust-restson
ExclusiveArch: %{rust_arches}
- rust-retry
ExclusiveArch: %{rust_arches}
- rust-rgb
ExclusiveArch: %{rust_arches}
- rust-ring
ExclusiveArch: %{rust_arches}
- rust-ripgrep
ExclusiveArch: %{rust_arches}
- rust-rle-decode-fast
ExclusiveArch: %{rust_arches}
- rust-rmp
ExclusiveArch: %{rust_arches}
- rust-rmp-serde
ExclusiveArch: %{rust_arches}
- rust-roff
ExclusiveArch: %{rust_arches}
- rust-ron
ExclusiveArch: %{rust_arches}
- rust-rpassword
ExclusiveArch: %{rust_arches}
- rust-rpick
ExclusiveArch: %{rust_arches}
- rust-rsa
ExclusiveArch: %{rust_arches}
- rust-rtnetlink
ExclusiveArch: %{rust_arches}
- rust-ruma-identifiers
ExclusiveArch: %{rust_arches}
- rust-rust-embed
ExclusiveArch: %{rust_arches}
- rust-rust-embed-impl
ExclusiveArch: %{rust_arches}
- rust-rust-embed-utils
ExclusiveArch: %{rust_arches}
- rust-rust-ini
ExclusiveArch: %{rust_arches}
- rust-rust-stemmers
ExclusiveArch: %{rust_arches}
- rust-rust_decimal
ExclusiveArch: %{rust_arches}
- rust-rust_hawktracer
ExclusiveArch: %{rust_arches}
- rust-rust_hawktracer_normal_macro
ExclusiveArch: %{rust_arches}
- rust-rust_hawktracer_proc_macro
ExclusiveArch: %{rust_arches}
- rust-rust_hawktracer_sys
ExclusiveArch: %{rust_arches}
- rust-rustc-demangle
ExclusiveArch: %{rust_arches}
- rust-rustc-hash
ExclusiveArch: %{rust_arches}
- rust-rustc-serialize
ExclusiveArch: %{rust_arches}
- rust-rustc-test
ExclusiveArch: %{rust_arches}
- rust-rustc_tools_util
ExclusiveArch: %{rust_arches}
- rust-rustc_version
ExclusiveArch: %{rust_arches}
- rust-rustdoc-stripper
ExclusiveArch: %{rust_arches}
- rust-rustfilt
ExclusiveArch: %{rust_arches}
- rust-rustfix
ExclusiveArch: %{rust_arches}
- rust-rustio
ExclusiveArch: %{rust_arches}
- rust-rustversion
ExclusiveArch: %{rust_arches}
- rust-rusty-fork
ExclusiveArch: %{rust_arches}
- rust-rustyline
ExclusiveArch: %{rust_arches}
- rust-rustyline-derive
ExclusiveArch: %{rust_arches}
- rust-ryu
ExclusiveArch: %{rust_arches}
- rust-safe-transmute
ExclusiveArch: %{rust_arches}
- rust-safemem
ExclusiveArch: %{rust_arches}
- rust-same-file
ExclusiveArch: %{rust_arches}
- rust-sass-rs
ExclusiveArch: %{rust_arches}
- rust-sass-sys
ExclusiveArch: %{rust_arches}
- rust-scan_fmt
ExclusiveArch: %{rust_arches}
- rust-scheduled-thread-pool
ExclusiveArch: %{rust_arches}
- rust-scoped-tls
ExclusiveArch: %{rust_arches}
- rust-scoped-tls-hkt
ExclusiveArch: %{rust_arches}
- rust-scoped_threadpool
ExclusiveArch: %{rust_arches}
- rust-scopeguard
ExclusiveArch: %{rust_arches}
- rust-scopetime
ExclusiveArch: %{rust_arches}
- rust-scroll
ExclusiveArch: %{rust_arches}
- rust-scroll_derive
ExclusiveArch: %{rust_arches}
- rust-sd
ExclusiveArch: %{rust_arches}
- rust-sd-notify
ExclusiveArch: %{rust_arches}
- rust-seahash
ExclusiveArch: %{rust_arches}
- rust-secrecy
ExclusiveArch: %{rust_arches}
- rust-secret-service
ExclusiveArch: %{rust_arches}
- rust-semver
ExclusiveArch: %{rust_arches}
- rust-semver-parser
ExclusiveArch: %{rust_arches}
- rust-semver-parser0.7
ExclusiveArch: %{rust_arches}
- rust-serde
ExclusiveArch: %{rust_arches}
- rust-serde-big-array
ExclusiveArch: %{rust_arches}
- rust-serde-pickle
ExclusiveArch: %{rust_arches}
- rust-serde-value
ExclusiveArch: %{rust_arches}
- rust-serde-xml-rs
ExclusiveArch: %{rust_arches}
- rust-serde_bytes
ExclusiveArch: %{rust_arches}
- rust-serde_cbor
ExclusiveArch: %{rust_arches}
- rust-serde_derive
ExclusiveArch: %{rust_arches}
- rust-serde_ignored
ExclusiveArch: %{rust_arches}
- rust-serde_json
ExclusiveArch: %{rust_arches}
- rust-serde_repr
ExclusiveArch: %{rust_arches}
- rust-serde_stacker
ExclusiveArch: %{rust_arches}
- rust-serde_test
ExclusiveArch: %{rust_arches}
- rust-serde_url_params
ExclusiveArch: %{rust_arches}
- rust-serde_urlencoded
ExclusiveArch: %{rust_arches}
- rust-serde_with_macros
ExclusiveArch: %{rust_arches}
- rust-serde_yaml
ExclusiveArch: %{rust_arches}
- rust-servo-fontconfig
ExclusiveArch: %{rust_arches}
- rust-servo-fontconfig-sys
ExclusiveArch: %{rust_arches}
- rust-sha-1
ExclusiveArch: %{rust_arches}
- rust-sha1
ExclusiveArch: %{rust_arches}
- rust-sha2
ExclusiveArch: %{rust_arches}
- rust-sha3
ExclusiveArch: %{rust_arches}
- rust-shared_child
ExclusiveArch: %{rust_arches}
- rust-shared_library
ExclusiveArch: %{rust_arches}
- rust-shell-escape
ExclusiveArch: %{rust_arches}
- rust-shell-words
ExclusiveArch: %{rust_arches}
- rust-shellexpand
ExclusiveArch: %{rust_arches}
- rust-shlex
ExclusiveArch: %{rust_arches}
- rust-signal-hook
ExclusiveArch: %{rust_arches}
- rust-signal-hook-registry
ExclusiveArch: %{rust_arches}
- rust-silver
ExclusiveArch: %{rust_arches}
- rust-simd_helpers
ExclusiveArch: %{rust_arches}
- rust-simple_asn1
ExclusiveArch: %{rust_arches}
- rust-simple_logger
ExclusiveArch: %{rust_arches}
- rust-simplelog
ExclusiveArch: %{rust_arches}
- rust-siphasher
ExclusiveArch: %{rust_arches}
- rust-size
ExclusiveArch: %{rust_arches}
- rust-sized-chunks
ExclusiveArch: %{rust_arches}
- rust-skeptic
ExclusiveArch: %{rust_arches}
- rust-skim
ExclusiveArch: %{rust_arches}
- rust-slab
ExclusiveArch: %{rust_arches}
- rust-slash-formatter
ExclusiveArch: %{rust_arches}
- rust-slice-deque
ExclusiveArch: %{rust_arches}
- rust-slog
ExclusiveArch: %{rust_arches}
- rust-slog-async
ExclusiveArch: %{rust_arches}
- rust-slog-scope
ExclusiveArch: %{rust_arches}
- rust-slog-term
ExclusiveArch: %{rust_arches}
- rust-slotmap
ExclusiveArch: %{rust_arches}
- rust-slug
ExclusiveArch: %{rust_arches}
- rust-sluice
ExclusiveArch: %{rust_arches}
- rust-smallvec
ExclusiveArch: %{rust_arches}
- rust-smart-default
ExclusiveArch: %{rust_arches}
- rust-smithay-client-toolkit
ExclusiveArch: %{rust_arches}
- rust-smithay-clipboard
ExclusiveArch: %{rust_arches}
- rust-snafu
ExclusiveArch: %{rust_arches}
- rust-snafu-derive
ExclusiveArch: %{rust_arches}
- rust-snowflake
ExclusiveArch: %{rust_arches}
- rust-socket2
ExclusiveArch: %{rust_arches}
- rust-soup-sys
ExclusiveArch: %{rust_arches}
- rust-sourceview
ExclusiveArch: %{rust_arches}
- rust-spin
ExclusiveArch: %{rust_arches}
- rust-spmc
ExclusiveArch: %{rust_arches}
- rust-ssh-key-dir
ExclusiveArch: %{rust_arches}
- rust-stable_deref_trait
ExclusiveArch: %{rust_arches}
- rust-stacker
ExclusiveArch: %{rust_arches}
- rust-standback
ExclusiveArch: %{rust_arches}
- rust-starship
ExclusiveArch: %{rust_arches}
- rust-starship_module_config_derive
ExclusiveArch: %{rust_arches}
- rust-static_assertions
ExclusiveArch: %{rust_arches}
- rust-statistical
ExclusiveArch: %{rust_arches}
- rust-stb_truetype
ExclusiveArch: %{rust_arches}
- rust-stream-cipher
ExclusiveArch: %{rust_arches}
- rust-streaming-stats
ExclusiveArch: %{rust_arches}
- rust-string
ExclusiveArch: %{rust_arches}
- rust-string_cache
ExclusiveArch: %{rust_arches}
- rust-string_cache_codegen
ExclusiveArch: %{rust_arches}
- rust-string_cache_shared
ExclusiveArch: %{rust_arches}
- rust-strings
ExclusiveArch: %{rust_arches}
- rust-strip-ansi-escapes
ExclusiveArch: %{rust_arches}
- rust-strsim
ExclusiveArch: %{rust_arches}
- rust-structopt
ExclusiveArch: %{rust_arches}
- rust-structopt-derive
ExclusiveArch: %{rust_arches}
- rust-structopt-derive0.2
ExclusiveArch: %{rust_arches}
- rust-structopt0.2
ExclusiveArch: %{rust_arches}
- rust-strum
ExclusiveArch: %{rust_arches}
- rust-strum_macros
ExclusiveArch: %{rust_arches}
- rust-subtle
ExclusiveArch: %{rust_arches}
- rust-sudo_plugin
ExclusiveArch: %{rust_arches}
- rust-sudo_plugin-sys
ExclusiveArch: %{rust_arches}
- rust-sval
ExclusiveArch: %{rust_arches}
- rust-sval_derive
ExclusiveArch: %{rust_arches}
- rust-sxd-document
ExclusiveArch: %{rust_arches}
- rust-syn
ExclusiveArch: %{rust_arches}
- rust-syn-mid
ExclusiveArch: %{rust_arches}
- rust-syn0.15
ExclusiveArch: %{rust_arches}
- rust-synom
ExclusiveArch: %{rust_arches}
- rust-synstructure
ExclusiveArch: %{rust_arches}
- rust-syntect
ExclusiveArch: %{rust_arches}
- rust-sys-info
ExclusiveArch: %{rust_arches}
- rust-sysinfo
ExclusiveArch: %{rust_arches}
- rust-system-deps
ExclusiveArch: %{rust_arches}
- rust-tabwriter
ExclusiveArch: %{rust_arches}
- rust-take
ExclusiveArch: %{rust_arches}
- rust-take_mut
ExclusiveArch: %{rust_arches}
- rust-tar
ExclusiveArch: %{rust_arches}
- rust-target-lexicon
ExclusiveArch: %{rust_arches}
- rust-tealdeer
ExclusiveArch: %{rust_arches}
- rust-teloxide
ExclusiveArch: %{rust_arches}
- rust-teloxide-macros
ExclusiveArch: %{rust_arches}
- rust-tempdir
ExclusiveArch: %{rust_arches}
- rust-tempfile
ExclusiveArch: %{rust_arches}
- rust-tendril
ExclusiveArch: %{rust_arches}
- rust-tera
ExclusiveArch: %{rust_arches}
- rust-term
ExclusiveArch: %{rust_arches}
- rust-term_grid
ExclusiveArch: %{rust_arches}
- rust-term_size
ExclusiveArch: %{rust_arches}
- rust-termcolor
ExclusiveArch: %{rust_arches}
- rust-terminal_size
ExclusiveArch: %{rust_arches}
- rust-terminfo
ExclusiveArch: %{rust_arches}
- rust-termion
ExclusiveArch: %{rust_arches}
- rust-termios
ExclusiveArch: %{rust_arches}
- rust-test-assembler
ExclusiveArch: %{rust_arches}
- rust-tester
ExclusiveArch: %{rust_arches}
- rust-testing_logger
ExclusiveArch: %{rust_arches}
- rust-textwrap
ExclusiveArch: %{rust_arches}
- rust-textwrap0.11
ExclusiveArch: %{rust_arches}
- rust-thiserror
ExclusiveArch: %{rust_arches}
- rust-thiserror-impl
ExclusiveArch: %{rust_arches}
- rust-thread-id
ExclusiveArch: %{rust_arches}
- rust-thread-scoped
ExclusiveArch: %{rust_arches}
- rust-thread_local
ExclusiveArch: %{rust_arches}
- rust-threadpool
ExclusiveArch: %{rust_arches}
- rust-tiff
ExclusiveArch: %{rust_arches}
- rust-tiger-digest
ExclusiveArch: %{rust_arches}
- rust-time
ExclusiveArch: %{rust_arches}
- rust-time-macros
ExclusiveArch: %{rust_arches}
- rust-time-macros-impl
ExclusiveArch: %{rust_arches}
- rust-time0.1
ExclusiveArch: %{rust_arches}
- rust-timebomb
ExclusiveArch: %{rust_arches}
- rust-timer
ExclusiveArch: %{rust_arches}
- rust-timerfd
ExclusiveArch: %{rust_arches}
- rust-tiny_http
ExclusiveArch: %{rust_arches}
- rust-tinytemplate
ExclusiveArch: %{rust_arches}
- rust-tinyvec
ExclusiveArch: %{rust_arches}
- rust-tokei
ExclusiveArch: %{rust_arches}
- rust-tokio
ExclusiveArch: %{rust_arches}
- rust-tokio-codec
ExclusiveArch: %{rust_arches}
- rust-tokio-core
ExclusiveArch: %{rust_arches}
- rust-tokio-current-thread
ExclusiveArch: %{rust_arches}
- rust-tokio-executor
ExclusiveArch: %{rust_arches}
- rust-tokio-fs
ExclusiveArch: %{rust_arches}
- rust-tokio-io
ExclusiveArch: %{rust_arches}
- rust-tokio-io-pool
ExclusiveArch: %{rust_arches}
- rust-tokio-macros
ExclusiveArch: %{rust_arches}
- rust-tokio-mock-task
ExclusiveArch: %{rust_arches}
- rust-tokio-openssl
ExclusiveArch: %{rust_arches}
- rust-tokio-reactor
ExclusiveArch: %{rust_arches}
- rust-tokio-socks
ExclusiveArch: %{rust_arches}
- rust-tokio-sync
ExclusiveArch: %{rust_arches}
- rust-tokio-tcp
ExclusiveArch: %{rust_arches}
- rust-tokio-test
ExclusiveArch: %{rust_arches}
- rust-tokio-threadpool
ExclusiveArch: %{rust_arches}
- rust-tokio-timer
ExclusiveArch: %{rust_arches}
- rust-tokio-tls
ExclusiveArch: %{rust_arches}
- rust-tokio-tls0.2
ExclusiveArch: %{rust_arches}
- rust-tokio-tungstenite
ExclusiveArch: %{rust_arches}
- rust-tokio-udp
ExclusiveArch: %{rust_arches}
- rust-tokio-uds
ExclusiveArch: %{rust_arches}
- rust-tokio-util
ExclusiveArch: %{rust_arches}
- rust-tokio-util0.2
ExclusiveArch: %{rust_arches}
- rust-tokio0.1
ExclusiveArch: %{rust_arches}
- rust-toml
ExclusiveArch: %{rust_arches}
- rust-toml0.4
ExclusiveArch: %{rust_arches}
- rust-tower-layer
ExclusiveArch: %{rust_arches}
- rust-tower-service
ExclusiveArch: %{rust_arches}
- rust-tower-test
ExclusiveArch: %{rust_arches}
- rust-tower-util
ExclusiveArch: %{rust_arches}
- rust-tpm2-policy
ExclusiveArch: %{rust_arches}
- rust-tracing
ExclusiveArch: %{rust_arches}
- rust-tracing-attributes
ExclusiveArch: %{rust_arches}
- rust-tracing-core
ExclusiveArch: %{rust_arches}
- rust-tracing-futures
ExclusiveArch: %{rust_arches}
- rust-traitobject
ExclusiveArch: %{rust_arches}
- rust-treebitmap
ExclusiveArch: %{rust_arches}
- rust-treeline
ExclusiveArch: %{rust_arches}
- rust-trust-dns-native-tls
ExclusiveArch: %{rust_arches}
- rust-trust-dns-openssl
ExclusiveArch: %{rust_arches}
- rust-trust-dns-proto
ExclusiveArch: %{rust_arches}
- rust-trust-dns-resolver
ExclusiveArch: %{rust_arches}
- rust-try-lock
ExclusiveArch: %{rust_arches}
- rust-try_from
ExclusiveArch: %{rust_arches}
- rust-try_or
ExclusiveArch: %{rust_arches}
- rust-trybuild
ExclusiveArch: %{rust_arches}
- rust-tss-esapi
ExclusiveArch: %{rust_arches}
- rust-tui
ExclusiveArch: %{rust_arches}
- rust-tui-react
ExclusiveArch: %{rust_arches}
- rust-tuikit
ExclusiveArch: %{rust_arches}
- rust-tungstenite
ExclusiveArch: %{rust_arches}
- rust-twoway
ExclusiveArch: %{rust_arches}
- rust-typeable
ExclusiveArch: %{rust_arches}
- rust-typed-arena
ExclusiveArch: %{rust_arches}
- rust-typemap
ExclusiveArch: %{rust_arches}
- rust-typenum
ExclusiveArch: %{rust_arches}
- rust-ucd-parse
ExclusiveArch: %{rust_arches}
- rust-ucd-trie
ExclusiveArch: %{rust_arches}
- rust-ucd-util
ExclusiveArch: %{rust_arches}
- rust-unchecked-index
ExclusiveArch: %{rust_arches}
- rust-unescape
ExclusiveArch: %{rust_arches}
- rust-unic-char-property
ExclusiveArch: %{rust_arches}
- rust-unic-char-range
ExclusiveArch: %{rust_arches}
- rust-unic-common
ExclusiveArch: %{rust_arches}
- rust-unic-segment
ExclusiveArch: %{rust_arches}
- rust-unic-ucd-category
ExclusiveArch: %{rust_arches}
- rust-unic-ucd-common
ExclusiveArch: %{rust_arches}
- rust-unic-ucd-segment
ExclusiveArch: %{rust_arches}
- rust-unic-ucd-version
ExclusiveArch: %{rust_arches}
- rust-unicase
ExclusiveArch: %{rust_arches}
- rust-unicase1
ExclusiveArch: %{rust_arches}
- rust-unicode-bidi
ExclusiveArch: %{rust_arches}
- rust-unicode-normalization
ExclusiveArch: %{rust_arches}
- rust-unicode-segmentation
ExclusiveArch: %{rust_arches}
- rust-unicode-width
ExclusiveArch: %{rust_arches}
- rust-unicode-xid
ExclusiveArch: %{rust_arches}
- rust-unicode-xid0.1
ExclusiveArch: %{rust_arches}
- rust-unicode_categories
ExclusiveArch: %{rust_arches}
- rust-unindent
ExclusiveArch: %{rust_arches}
- rust-unix_socket
ExclusiveArch: %{rust_arches}
- rust-unreachable
ExclusiveArch: %{rust_arches}
- rust-unsafe-any
ExclusiveArch: %{rust_arches}
- rust-untrusted
ExclusiveArch: %{rust_arches}
- rust-uom
ExclusiveArch: %{rust_arches}
- rust-url
ExclusiveArch: %{rust_arches}
- rust-url1
ExclusiveArch: %{rust_arches}
- rust-url_serde
ExclusiveArch: %{rust_arches}
- rust-urlencoding
ExclusiveArch: %{rust_arches}
- rust-urlocator
ExclusiveArch: %{rust_arches}
- rust-urlshortener
ExclusiveArch: %{rust_arches}
- rust-users
ExclusiveArch: %{rust_arches}
- rust-utf-8
ExclusiveArch: %{rust_arches}
- rust-utf8-ranges
ExclusiveArch: %{rust_arches}
- rust-utf8parse
ExclusiveArch: %{rust_arches}
- rust-uuid
ExclusiveArch: %{rust_arches}
- rust-uuid0.7
ExclusiveArch: %{rust_arches}
- rust-v_escape
ExclusiveArch: %{rust_arches}
- rust-v_escape_derive
ExclusiveArch: %{rust_arches}
- rust-v_htmlescape
ExclusiveArch: %{rust_arches}
- rust-varlink
ExclusiveArch: %{rust_arches}
- rust-varlink-cli
ExclusiveArch: %{rust_arches}
- rust-varlink_generator
ExclusiveArch: %{rust_arches}
- rust-varlink_parser
ExclusiveArch: %{rust_arches}
- rust-varlink_stdinterfaces
ExclusiveArch: %{rust_arches}
- rust-vec_map
ExclusiveArch: %{rust_arches}
- rust-vergen
ExclusiveArch: %{rust_arches}
- rust-version-compare
ExclusiveArch: %{rust_arches}
- rust-version-sync
ExclusiveArch: %{rust_arches}
- rust-version-sync0.8
ExclusiveArch: %{rust_arches}
- rust-version_check
ExclusiveArch: %{rust_arches}
- rust-vmw_backdoor
ExclusiveArch: %{rust_arches}
- rust-void
ExclusiveArch: %{rust_arches}
- rust-vte
ExclusiveArch: %{rust_arches}
- rust-vte_generate_state_changes
ExclusiveArch: %{rust_arches}
- rust-wait-timeout
ExclusiveArch: %{rust_arches}
- rust-walkdir
ExclusiveArch: %{rust_arches}
- rust-want
ExclusiveArch: %{rust_arches}
- rust-warp
ExclusiveArch: %{rust_arches}
- rust-wasm-bindgen
ExclusiveArch: %{rust_arches}
- rust-wasm-bindgen-backend
ExclusiveArch: %{rust_arches}
- rust-wasm-bindgen-macro
ExclusiveArch: %{rust_arches}
- rust-wasm-bindgen-macro-support
ExclusiveArch: %{rust_arches}
- rust-wasm-bindgen-shared
ExclusiveArch: %{rust_arches}
- rust-wasm-bindgen-test-macro
ExclusiveArch: %{rust_arches}
- rust-wayland-client
ExclusiveArch: %{rust_arches}
- rust-wayland-commons
ExclusiveArch: %{rust_arches}
- rust-wayland-cursor
ExclusiveArch: %{rust_arches}
- rust-wayland-protocols
ExclusiveArch: %{rust_arches}
- rust-wayland-scanner
ExclusiveArch: %{rust_arches}
- rust-wayland-server
ExclusiveArch: %{rust_arches}
- rust-wayland-sys
ExclusiveArch: %{rust_arches}
- rust-web-sys
ExclusiveArch: %{rust_arches}
- rust-webkit2gtk
ExclusiveArch: %{rust_arches}
- rust-webkit2gtk-sys
ExclusiveArch: %{rust_arches}
- rust-websocket
ExclusiveArch: %{rust_arches}
- rust-websocket-base
ExclusiveArch: %{rust_arches}
- rust-which
ExclusiveArch: %{rust_arches}
- rust-wild
ExclusiveArch: %{rust_arches}
- rust-ws
ExclusiveArch: %{rust_arches}
- rust-x11
ExclusiveArch: %{rust_arches}
- rust-x11-clipboard
ExclusiveArch: %{rust_arches}
- rust-x11-dl
ExclusiveArch: %{rust_arches}
- rust-xattr
ExclusiveArch: %{rust_arches}
- rust-xcb
ExclusiveArch: %{rust_arches}
- rust-xcursor
ExclusiveArch: %{rust_arches}
- rust-xdg
ExclusiveArch: %{rust_arches}
- rust-xkbcommon
ExclusiveArch: %{rust_arches}
- rust-xml-rs
ExclusiveArch: %{rust_arches}
- rust-xml5ever
ExclusiveArch: %{rust_arches}
- rust-xz2
ExclusiveArch: %{rust_arches}
- rust-y4m
ExclusiveArch: %{rust_arches}
- rust-yaml-rust
ExclusiveArch: %{rust_arches}
- rust-yaml-rust0.3
ExclusiveArch: %{rust_arches}
- rust-ybaas
ExclusiveArch: %{rust_arches}
- rust-ytop
ExclusiveArch: %{rust_arches}
- rust-yubibomb
ExclusiveArch: %{rust_arches}
- rust-yup-oauth2
ExclusiveArch: %{rust_arches}
- rust-zbus_macros
ExclusiveArch: %{rust_arches}
- rust-zeroize
ExclusiveArch: %{rust_arches}
- rust-zeroize_derive
ExclusiveArch: %{rust_arches}
- rust-zincati
ExclusiveArch: %{rust_arches}
- rust-zip
ExclusiveArch: %{rust_arches}
- rust-zoneinfo_compiled
ExclusiveArch: %{rust_arches}
- rust-zoxide
ExclusiveArch: %{rust_arches}
- rust-zram-generator
ExclusiveArch: %{rust_arches}
- rust-zstd
ExclusiveArch: %{rust_arches}
- rust-zstd-safe
ExclusiveArch: %{rust_arches}
- rust-zstd-sys
ExclusiveArch: %{rust_arches}
- rust-zvariant
ExclusiveArch: %{rust_arches}
- rust-zvariant_derive
ExclusiveArch: %{rust_arches}
- s390utils
ExclusiveArch: s390 s390x
- safetyblanket
ExclusiveArch: %{arm} %{ix86} x86_64 aarch64 ppc64le
- sagemath
ExclusiveArch: aarch64 %{ix86} x86_64 ppc sparcv9
- sbcl
ExclusiveArch: %{arm} %{ix86} x86_64 ppc sparcv9 aarch64
- sbd
ExclusiveArch: i686 x86_64 s390x aarch64 ppc64le
- sbsigntools
ExclusiveArch: x86_64 aarch64 %{arm} %{ix86}
- seabios
ExclusiveArch: x86_64
- seamonkey
ExclusiveArch: x86_64
- servicelog
ExclusiveArch: ppc %{power64}
- sgabios
ExclusiveArch: %{ix86} x86_64
- sharpfont
ExclusiveArch: %mono_arches
- sharpziplib
ExclusiveArch: %{mono_arches}
- shim
ExclusiveArch: %{efi}
- shim-unsigned-aarch64
ExclusiveArch: aarch64
- shim-unsigned-x64
ExclusiveArch: x86_64
- sigul
ExclusiveArch: x86_64
- skychart
ExclusiveArch: %{fpc_arches}
- snapd
ExclusiveArch: %{?go_arches:%{go_arches}}%{!?go_arches:%{ix86} x86_64 %{arm}}
ExclusiveArch: %{ix86} x86_64 %{arm} aarch64 ppc64le s390x
- soup-sharp
ExclusiveArch: %{mono_arches}
- source-to-image
ExclusiveArch: %{?go_arches:%{go_arches}}%{!?go_arches:%{ix86} x86_64 %{arm}}
- sparkleshare
ExclusiveArch: %{mono_arches}
- spicctrl
ExclusiveArch: %{ix86} x86_64
- spice
ExclusiveArch: x86_64
ExclusiveArch: %{ix86} x86_64 %{arm} aarch64
- springlobby
ExclusiveArch: %{ix86} x86_64
- squeekboard
ExclusiveArch: %{rust_arches}
- startdde
ExclusiveArch: %{?go_arches:%{go_arches}}%{!?go_arches:%{ix86} x86_64 %{arm}}
- statsd
ExclusiveArch: %{nodejs_arches} noarch
- stratis-cli
ExclusiveArch: %{rust_arches} noarch
- stratisd
ExclusiveArch: %{rust_arches}
- stripesnoop
ExclusiveArch: %{ix86} x86_64
- supercollider
ExclusiveArch: %{qt5_qtwebengine_arches}
- supermin
ExclusiveArch: %{kernel_arches}
- svt-av1
ExclusiveArch: x86_64
- svt-vp9
ExclusiveArch: x86_64
- swift-lang
ExclusiveArch: x86_64 aarch64
- sysbench
ExclusiveArch: %{arm} %{ix86} x86_64 %{mips}
ExclusiveArch: %{arm} %{ix86} x86_64 %{mips} aarch64
- syslinux
ExclusiveArch: %{ix86} x86_64
ExclusiveArch: %{ix86} x86_64
- taglib-sharp
ExclusiveArch: %{mono_arches}
- tarantool
ExclusiveArch: %{ix86} x86_64
- tboot
ExclusiveArch: %{ix86} x86_64
- tdlib
ExclusiveArch: x86_64
- templates_parser
ExclusiveArch: %GPRbuild_arches
- ternimal
ExclusiveArch: %{rust_arches}
- testcloud
ExclusiveArch: %{kernel_arches} noarch
- themonospot-base
ExclusiveArch: %mono_arches
- themonospot-console
ExclusiveArch: %mono_arches
- themonospot-gui-gtk
ExclusiveArch: %mono_arches
- themonospot-plugin-avi
ExclusiveArch: %mono_arches
- themonospot-plugin-mkv
ExclusiveArch: %mono_arches
- thermald
ExclusiveArch: %{ix86} x86_64
- tilix
ExclusiveArch: %{ldc_arches}
- tmux-top
ExclusiveArch: %{go_arches}
- tomboy
ExclusiveArch: %{mono_arches}
- torbrowser-launcher
ExclusiveArch: %{ix86} x86_64
- tuned-profiles-nfv-host-bin
ExclusiveArch: %{ix86} x86_64
- uClibc
ExclusiveArch: %{arm} %{ix86} x86_64 %{mips}
- ucx
ExclusiveArch: aarch64 ppc64le x86_64
- ugene
ExclusiveArch: %{ix86} x86_64
- uglify-js
ExclusiveArch: %{nodejs_arches} noarch
- uglify-js1
ExclusiveArch: %{nodejs_arches} noarch
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
- unetbootin
ExclusiveArch: %{ix86} x86_64
- ursa-major
ExclusiveArch: noarch aarch64 ppc64le s390x x86_64
- v8-314
ExclusiveArch: %{ix86} x86_64 %{arm} mips mipsel ppc ppc64
- valgrind
ExclusiveArch: %{ix86} x86_64 ppc ppc64 ppc64le s390x armv7hl aarch64
- vapoursynth
ExclusiveArch: %{ix86} x86_64
- vboot-utils
ExclusiveArch: %{arm} aarch64 %{ix86} x86_64
- vim-go
ExclusiveArch: %{?golang_arches}%{!?golang_arches:%{ix86} x86_64 %{arm}}
- virt-p2v
ExclusiveArch: x86_64
- virtualbox-guest-additions
ExclusiveArch: i686 x86_64
- virtualplanet
ExclusiveArch: %{fpc_arches}
- vkd3d
ExclusiveArch: %{ix86} x86_64 %{arm}
ExclusiveArch: %{ix86} x86_64 %{arm} aarch64
- vmaf
ExclusiveArch: x86_64
- vmem
ExclusiveArch: x86_64
- vmemcache
ExclusiveArch: x86_64 ppc64 ppc64le s390x aarch64
- vrq
ExclusiveArch: %{ix86} x86_64
- warsow
ExclusiveArch: %{ix86} x86_64 %{arm}
- warsow-data
ExclusiveArch: %{ix86} x86_64 %{arm} noarch
ExclusiveArch: %{ix86} x86_64 %{arm}
- webkit2-sharp
ExclusiveArch: %mono_arches
- wine
ExclusiveArch: %{ix86} x86_64 %{arm} aarch64
ExclusiveArch: %{ix86} %{arm}
- wine-dxvk
ExclusiveArch: %{ix86} x86_64
- winetricks
ExclusiveArch: %{ix86} x86_64 %{arm} aarch64
- wxMaxima
ExclusiveArch: %{arm} %{ix86} x86_64 aarch64 ppc sparcv9
- x2goclient
ExclusiveArch: x86_64
- xe-guest-utilities-latest
ExclusiveArch: %{ix86} x86_64
- xen
ExclusiveArch: %{ix86} x86_64 armv7hl aarch64
- xmlada
ExclusiveArch: %{GPRbuild_arches}
- xorg-x11-drv-armsoc
ExclusiveArch: %{arm} aarch64
- xorg-x11-drv-intel
ExclusiveArch: %{ix86} x86_64
- xorg-x11-drv-openchrome
ExclusiveArch: %{ix86} x86_64
- xorg-x11-drv-vesa
ExclusiveArch: %{ix86} x86_64
- xorg-x11-drv-vmware
ExclusiveArch: %{ix86} x86_64 ia64
- xsp
ExclusiveArch: %mono_arches
- yarnpkg
ExclusiveArch: %{nodejs_arches} noarch
- zeromq-ada
ExclusiveArch: %{GPRbuild_arches}
- zlib-ada
ExclusiveArch: %{GPRbuild_arches}
- zlib-ng
ExclusiveArch: aarch64 i686 ppc64le s390x x86_64
- zola
ExclusiveArch: %{rust_arches}
3 years, 8 months
Architecture specific change in rpms/netty.git
by githook-noreply@fedoraproject.org
The package rpms/netty.git has added or updated architecture specific content in its
spec file (ExclusiveArch/ExcludeArch or %ifarch/%ifnarch) in commit(s):
https://src.fedoraproject.org/cgit/rpms/netty.git/commit/?id=342e6b392cd9....
Change:
-%ifarch %{arm}
Thanks.
Full change:
============
commit 342e6b392cd905be34a8918ca862d2dca9a3dcd8
Author: Mat Booth <mat.booth(a)redhat.com>
Date: Mon Sep 7 14:53:52 2020 +0100
Update to latest upstream version
Native bits were not used by anything, so package is now noarch
diff --git a/.gitignore b/.gitignore
index 859e799..488860d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,2 @@
-/netty-4.0.42.Final.tar.gz
-/netty-4.1.13.Final.tar.gz
+/netty-*.tar.gz
+/*.src.rpm
diff --git a/0001-Remove-optional-dep-Blockhound.patch b/0001-Remove-optional-dep-Blockhound.patch
new file mode 100644
index 0000000..783b2f8
--- /dev/null
+++ b/0001-Remove-optional-dep-Blockhound.patch
@@ -0,0 +1,633 @@
+From 14fa8d4afda0fa1a31a2591298dc5c18e08dab1f Mon Sep 17 00:00:00 2001
+From: Mat Booth <mat.booth(a)redhat.com>
+Date: Mon, 7 Sep 2020 12:17:31 +0100
+Subject: [PATCH 1/5] Remove optional dep Blockhound
+
+---
+ common/pom.xml | 5 -
+ .../java/io/netty/util/internal/Hidden.java | 113 ---------
+ ...ockhound.integration.BlockHoundIntegration | 14 -
+ pom.xml | 7 -
+ transport-blockhound-tests/pom.xml | 92 -------
+ .../NettyBlockHoundIntegrationTest.java | 239 ------------------
+ .../netty/util/internal/localhost_server.key | 28 --
+ .../netty/util/internal/localhost_server.pem | 17 --
+ .../io/netty/util/internal/mutual_auth_ca.pem | 19 --
+ 9 files changed, 534 deletions(-)
+ delete mode 100644 common/src/main/java/io/netty/util/internal/Hidden.java
+ delete mode 100644 common/src/main/resources/META-INF/services/reactor.blockhound.integration.BlockHoundIntegration
+ delete mode 100644 transport-blockhound-tests/pom.xml
+ delete mode 100644 transport-blockhound-tests/src/test/java/io/netty/util/internal/NettyBlockHoundIntegrationTest.java
+ delete mode 100644 transport-blockhound-tests/src/test/resources/io/netty/util/internal/localhost_server.key
+ delete mode 100644 transport-blockhound-tests/src/test/resources/io/netty/util/internal/localhost_server.pem
+ delete mode 100644 transport-blockhound-tests/src/test/resources/io/netty/util/internal/mutual_auth_ca.pem
+
+diff --git a/common/pom.xml b/common/pom.xml
+index 706279177a..abc73161eb 100644
+--- a/common/pom.xml
++++ b/common/pom.xml
+@@ -78,11 +78,6 @@
+ <artifactId>log4j-core</artifactId>
+ <scope>test</scope>
+ </dependency>
+- <dependency>
+- <groupId>io.projectreactor.tools</groupId>
+- <artifactId>blockhound</artifactId>
+- <optional>true</optional>
+- </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-core</artifactId>
+diff --git a/common/src/main/java/io/netty/util/internal/Hidden.java b/common/src/main/java/io/netty/util/internal/Hidden.java
+deleted file mode 100644
+index 7fd6d08396..0000000000
+--- a/common/src/main/java/io/netty/util/internal/Hidden.java
++++ /dev/null
+@@ -1,113 +0,0 @@
+-/*
+- * Copyright 2019 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- * http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-
+-package io.netty.util.internal;
+-
+-import io.netty.util.concurrent.FastThreadLocalThread;
+-import reactor.blockhound.BlockHound;
+-import reactor.blockhound.integration.BlockHoundIntegration;
+-
+-import java.util.function.Function;
+-import java.util.function.Predicate;
+-
+-/**
+- * Contains classes that must be have public visibility but are not public API.
+- */
+-class Hidden {
+-
+- /**
+- * This class integrates Netty with BlockHound.
+- * <p>
+- * It is public but only because of the ServiceLoader's limitations
+- * and SHOULD NOT be considered a public API.
+- */
+- @UnstableApi
+- @SuppressJava6Requirement(reason = "BlockHound is Java 8+, but this class is only loaded by it's SPI")
+- public static final class NettyBlockHoundIntegration implements BlockHoundIntegration {
+-
+- @Override
+- public void applyTo(BlockHound.Builder builder) {
+- builder.allowBlockingCallsInside(
+- "io.netty.channel.nio.NioEventLoop",
+- "handleLoopException"
+- );
+-
+- builder.allowBlockingCallsInside(
+- "io.netty.channel.kqueue.KQueueEventLoop",
+- "handleLoopException"
+- );
+-
+- builder.allowBlockingCallsInside(
+- "io.netty.channel.epoll.EpollEventLoop",
+- "handleLoopException"
+- );
+-
+- builder.allowBlockingCallsInside(
+- "io.netty.util.HashedWheelTimer$Worker",
+- "waitForNextTick"
+- );
+-
+- builder.allowBlockingCallsInside(
+- "io.netty.util.concurrent.SingleThreadEventExecutor",
+- "confirmShutdown"
+- );
+-
+- builder.allowBlockingCallsInside(
+- "io.netty.handler.ssl.SslHandler",
+- "handshake"
+- );
+-
+- builder.allowBlockingCallsInside(
+- "io.netty.handler.ssl.SslHandler",
+- "runAllDelegatedTasks"
+- );
+-
+- builder.allowBlockingCallsInside(
+- "io.netty.util.concurrent.GlobalEventExecutor",
+- "takeTask");
+-
+- builder.allowBlockingCallsInside(
+- "io.netty.util.concurrent.GlobalEventExecutor",
+- "addTask");
+-
+- builder.allowBlockingCallsInside(
+- "io.netty.util.concurrent.SingleThreadEventExecutor",
+- "takeTask");
+-
+- builder.allowBlockingCallsInside(
+- "io.netty.handler.ssl.ReferenceCountedOpenSslClientContext$ExtendedTrustManagerVerifyCallback",
+- "verify");
+-
+- builder.nonBlockingThreadPredicate(new Function<Predicate<Thread>, Predicate<Thread>>() {
+- @Override
+- public Predicate<Thread> apply(final Predicate<Thread> p) {
+- return new Predicate<Thread>() {
+- @Override
+- @SuppressJava6Requirement(reason = "Predicate#test")
+- public boolean test(Thread thread) {
+- return p.test(thread) || thread instanceof FastThreadLocalThread;
+- }
+- };
+- }
+- });
+- }
+-
+- @Override
+- public int compareTo(BlockHoundIntegration o) {
+- return 0;
+- }
+- }
+-}
+diff --git a/common/src/main/resources/META-INF/services/reactor.blockhound.integration.BlockHoundIntegration b/common/src/main/resources/META-INF/services/reactor.blockhound.integration.BlockHoundIntegration
+deleted file mode 100644
+index 5cf376dd8c..0000000000
+--- a/common/src/main/resources/META-INF/services/reactor.blockhound.integration.BlockHoundIntegration
++++ /dev/null
+@@ -1,14 +0,0 @@
+-# Copyright 2019 The Netty Project
+-#
+-# The Netty Project licenses this file to you under the Apache License,
+-# version 2.0 (the "License"); you may not use this file except in compliance
+-# with the License. You may obtain a copy of the License at:
+-#
+-# http://www.apache.org/licenses/LICENSE-2.0
+-#
+-# Unless required by applicable law or agreed to in writing, software
+-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+-# License for the specific language governing permissions and limitations
+-# under the License.
+-io.netty.util.internal.Hidden$NettyBlockHoundIntegration
+\ No newline at end of file
+diff --git a/pom.xml b/pom.xml
+index d00e3e88e0..d548aa5513 100644
+--- a/pom.xml
++++ b/pom.xml
+@@ -416,7 +416,6 @@
+ <module>testsuite-osgi</module>
+ <module>testsuite-shading</module>
+ <module>testsuite-native-image</module>
+- <module>transport-blockhound-tests</module>
+ <module>microbench</module>
+ <module>bom</module>
+ </modules>
+@@ -717,12 +716,6 @@
+ <scope>test</scope>
+ </dependency>
+
+- <!-- BlockHound integration -->
+- <dependency>
+- <groupId>io.projectreactor.tools</groupId>
+- <artifactId>blockhound</artifactId>
+- <version>1.0.3.RELEASE</version>
+- </dependency>
+ </dependencies>
+ </dependencyManagement>
+
+diff --git a/transport-blockhound-tests/pom.xml b/transport-blockhound-tests/pom.xml
+deleted file mode 100644
+index 359accd3c4..0000000000
+--- a/transport-blockhound-tests/pom.xml
++++ /dev/null
+@@ -1,92 +0,0 @@
+-<?xml version="1.0" encoding="UTF-8"?>
+-<!--
+- ~ Copyright 2019 The Netty Project
+- ~
+- ~ The Netty Project licenses this file to you under the Apache License,
+- ~ version 2.0 (the "License"); you may not use this file except in compliance
+- ~ with the License. You may obtain a copy of the License at:
+- ~
+- ~ http://www.apache.org/licenses/LICENSE-2.0
+- ~
+- ~ Unless required by applicable law or agreed to in writing, software
+- ~ distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- ~ WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- ~ License for the specific language governing permissions and limitations
+- ~ under the License.
+- -->
+-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+-
+- <modelVersion>4.0.0</modelVersion>
+- <parent>
+- <groupId>io.netty</groupId>
+- <artifactId>netty-parent</artifactId>
+- <version>4.1.51.Final</version>
+- </parent>
+-
+- <artifactId>netty-transport-blockhound-tests</artifactId>
+- <packaging>jar</packaging>
+- <description>
+- Tests for the BlockHound integration.
+- </description>
+-
+- <name>Netty/Transport/BlockHound/Tests</name>
+-
+- <profiles>
+- <profile>
+- <id>java13</id>
+- <activation>
+- <jdk>13</jdk>
+- </activation>
+- <properties>
+- <argLine.common>-XX:+AllowRedefinitionToAddDeleteMethods</argLine.common>
+- </properties>
+- </profile>
+- <profile>
+- <id>java14</id>
+- <activation>
+- <jdk>14</jdk>
+- </activation>
+- <properties>
+- <argLine.common>-XX:+AllowRedefinitionToAddDeleteMethods</argLine.common>
+- </properties>
+- </profile>
+- </profiles>
+-
+- <properties>
+- <maven.compiler.source>1.8</maven.compiler.source>
+- <maven.compiler.target>1.8</maven.compiler.target>
+- <!-- Needed for SelfSignedCertificate -->
+- <argLine.java9.extras>--add-exports java.base/sun.security.x509=ALL-UNNAMED</argLine.java9.extras>
+- <skipJapicmp>true</skipJapicmp>
+- </properties>
+-
+- <dependencies>
+- <dependency>
+- <groupId>${project.groupId}</groupId>
+- <artifactId>netty-transport</artifactId>
+- <version>${project.version}</version>
+- </dependency>
+- <dependency>
+- <groupId>${project.groupId}</groupId>
+- <artifactId>netty-handler</artifactId>
+- <version>${project.version}</version>
+- </dependency>
+- <dependency>
+- <groupId>${project.groupId}</groupId>
+- <artifactId>${tcnative.artifactId}</artifactId>
+- <classifier>${tcnative.classifier}</classifier>
+- <optional>true</optional>
+- </dependency>
+-
+- <dependency>
+- <groupId>org.bouncycastle</groupId>
+- <artifactId>bcpkix-jdk15on</artifactId>
+- <optional>true</optional>
+- </dependency>
+- <dependency>
+- <groupId>io.projectreactor.tools</groupId>
+- <artifactId>blockhound</artifactId>
+- <scope>test</scope>
+- </dependency>
+- </dependencies>
+-</project>
+diff --git a/transport-blockhound-tests/src/test/java/io/netty/util/internal/NettyBlockHoundIntegrationTest.java b/transport-blockhound-tests/src/test/java/io/netty/util/internal/NettyBlockHoundIntegrationTest.java
+deleted file mode 100644
+index 58e9284370..0000000000
+--- a/transport-blockhound-tests/src/test/java/io/netty/util/internal/NettyBlockHoundIntegrationTest.java
++++ /dev/null
+@@ -1,239 +0,0 @@
+-/*
+- * Copyright 2019 The Netty Project
+-
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+-
+- * http://www.apache.org/licenses/LICENSE-2.0
+-
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-package io.netty.util.internal;
+-
+-import io.netty.bootstrap.Bootstrap;
+-import io.netty.bootstrap.ServerBootstrap;
+-import io.netty.buffer.UnpooledByteBufAllocator;
+-import io.netty.channel.Channel;
+-import io.netty.channel.ChannelFuture;
+-import io.netty.channel.ChannelHandlerContext;
+-import io.netty.channel.ChannelInboundHandlerAdapter;
+-import io.netty.channel.ChannelInitializer;
+-import io.netty.channel.EventLoopGroup;
+-import io.netty.channel.nio.NioEventLoopGroup;
+-import io.netty.channel.socket.nio.NioServerSocketChannel;
+-import io.netty.channel.socket.nio.NioSocketChannel;
+-import io.netty.handler.ssl.SslContext;
+-import io.netty.handler.ssl.SslContextBuilder;
+-import io.netty.handler.ssl.SslHandler;
+-import io.netty.handler.ssl.SslHandshakeCompletionEvent;
+-import io.netty.handler.ssl.SslProvider;
+-import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
+-import io.netty.handler.ssl.util.SelfSignedCertificate;
+-import io.netty.util.ReferenceCountUtil;
+-import io.netty.util.concurrent.DefaultThreadFactory;
+-import io.netty.util.concurrent.EventExecutor;
+-import io.netty.util.concurrent.GlobalEventExecutor;
+-import io.netty.util.concurrent.ImmediateEventExecutor;
+-import io.netty.util.concurrent.ImmediateExecutor;
+-import io.netty.util.concurrent.ScheduledFuture;
+-import io.netty.util.concurrent.SingleThreadEventExecutor;
+-import io.netty.util.internal.Hidden.NettyBlockHoundIntegration;
+-import org.hamcrest.Matchers;
+-import org.junit.BeforeClass;
+-import org.junit.Test;
+-import reactor.blockhound.BlockHound;
+-import reactor.blockhound.BlockingOperationError;
+-import reactor.blockhound.integration.BlockHoundIntegration;
+-
+-import java.net.InetSocketAddress;
+-import java.util.ServiceLoader;
+-import java.util.concurrent.CountDownLatch;
+-import java.util.concurrent.ExecutionException;
+-import java.util.concurrent.Executor;
+-import java.util.concurrent.ExecutorService;
+-import java.util.concurrent.Executors;
+-import java.util.concurrent.FutureTask;
+-import java.util.concurrent.TimeUnit;
+-
+-import static org.junit.Assert.assertThat;
+-import static org.junit.Assert.assertTrue;
+-import static org.junit.Assert.fail;
+-
+-public class NettyBlockHoundIntegrationTest {
+-
+- @BeforeClass
+- public static void setUpClass() {
+- BlockHound.install();
+- }
+-
+- @Test
+- public void testServiceLoader() {
+- for (BlockHoundIntegration integration : ServiceLoader.load(BlockHoundIntegration.class)) {
+- if (integration instanceof NettyBlockHoundIntegration) {
+- return;
+- }
+- }
+-
+- fail("NettyBlockHoundIntegration cannot be loaded with ServiceLoader");
+- }
+-
+- @Test
+- public void testBlockingCallsInNettyThreads() throws Exception {
+- final FutureTask<Void> future = new FutureTask<>(() -> {
+- Thread.sleep(0);
+- return null;
+- });
+- GlobalEventExecutor.INSTANCE.execute(future);
+-
+- try {
+- future.get(5, TimeUnit.SECONDS);
+- fail("Expected an exception due to a blocking call but none was thrown");
+- } catch (ExecutionException e) {
+- assertThat(e.getCause(), Matchers.instanceOf(BlockingOperationError.class));
+- }
+- }
+-
+- @Test(timeout = 5000L)
+- public void testGlobalEventExecutorTakeTask() throws InterruptedException {
+- testEventExecutorTakeTask(GlobalEventExecutor.INSTANCE);
+- }
+-
+- @Test(timeout = 5000L)
+- public void testSingleThreadEventExecutorTakeTask() throws InterruptedException {
+- SingleThreadEventExecutor executor =
+- new SingleThreadEventExecutor(null, new DefaultThreadFactory("test"), true) {
+- @Override
+- protected void run() {
+- while (!confirmShutdown()) {
+- Runnable task = takeTask();
+- if (task != null) {
+- task.run();
+- }
+- }
+- }
+- };
+- testEventExecutorTakeTask(executor);
+- }
+-
+- private static void testEventExecutorTakeTask(EventExecutor eventExecutor) throws InterruptedException {
+- CountDownLatch latch = new CountDownLatch(1);
+- ScheduledFuture<?> f = eventExecutor.schedule(latch::countDown, 10, TimeUnit.MILLISECONDS);
+- f.sync();
+- latch.await();
+- }
+-
+- // Tests copied from io.netty.handler.ssl.SslHandlerTest
+- @Test
+- public void testHandshakeWithExecutorThatExecuteDirectory() throws Exception {
+- testHandshakeWithExecutor(Runnable::run);
+- }
+-
+- @Test
+- public void testHandshakeWithImmediateExecutor() throws Exception {
+- testHandshakeWithExecutor(ImmediateExecutor.INSTANCE);
+- }
+-
+- @Test
+- public void testHandshakeWithImmediateEventExecutor() throws Exception {
+- testHandshakeWithExecutor(ImmediateEventExecutor.INSTANCE);
+- }
+-
+- @Test
+- public void testHandshakeWithExecutor() throws Exception {
+- ExecutorService executorService = Executors.newCachedThreadPool();
+- try {
+- testHandshakeWithExecutor(executorService);
+- } finally {
+- executorService.shutdown();
+- }
+- }
+-
+- @Test
+- public void testTrustManagerVerify() throws Exception {
+- final SslContext sslClientCtx =
+- SslContextBuilder.forClient()
+- .trustManager(ResourcesUtil.getFile(getClass(), "mutual_auth_ca.pem"))
+- .build();
+-
+- final SslContext sslServerCtx =
+- SslContextBuilder.forServer(ResourcesUtil.getFile(getClass(), "localhost_server.pem"),
+- ResourcesUtil.getFile(getClass(), "localhost_server.key"),
+- null)
+- .build();
+-
+- final SslHandler clientSslHandler = sslClientCtx.newHandler(UnpooledByteBufAllocator.DEFAULT);
+- final SslHandler serverSslHandler = sslServerCtx.newHandler(UnpooledByteBufAllocator.DEFAULT);
+-
+- testHandshake(sslClientCtx, clientSslHandler, serverSslHandler);
+- }
+-
+- private static void testHandshakeWithExecutor(Executor executor) throws Exception {
+- String tlsVersion = "TLSv1.2";
+- final SslContext sslClientCtx = SslContextBuilder.forClient()
+- .trustManager(InsecureTrustManagerFactory.INSTANCE)
+- .sslProvider(SslProvider.JDK).protocols(tlsVersion).build();
+-
+- final SelfSignedCertificate cert = new SelfSignedCertificate();
+- final SslContext sslServerCtx = SslContextBuilder.forServer(cert.key(), cert.cert())
+- .sslProvider(SslProvider.JDK).protocols(tlsVersion).build();
+-
+- final SslHandler clientSslHandler = sslClientCtx.newHandler(UnpooledByteBufAllocator.DEFAULT, executor);
+- final SslHandler serverSslHandler = sslServerCtx.newHandler(UnpooledByteBufAllocator.DEFAULT, executor);
+-
+- testHandshake(sslClientCtx, clientSslHandler, serverSslHandler);
+- }
+-
+- private static void testHandshake(SslContext sslClientCtx, SslHandler clientSslHandler,
+- SslHandler serverSslHandler) throws Exception {
+- EventLoopGroup group = new NioEventLoopGroup();
+- Channel sc = null;
+- Channel cc = null;
+- try {
+- sc = new ServerBootstrap()
+- .group(group)
+- .channel(NioServerSocketChannel.class)
+- .childHandler(serverSslHandler)
+- .bind(new InetSocketAddress(0)).syncUninterruptibly().channel();
+-
+- ChannelFuture future = new Bootstrap()
+- .group(group)
+- .channel(NioSocketChannel.class)
+- .handler(new ChannelInitializer<Channel>() {
+- @Override
+- protected void initChannel(Channel ch) {
+- ch.pipeline()
+- .addLast(clientSslHandler)
+- .addLast(new ChannelInboundHandlerAdapter() {
+-
+- @Override
+- public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
+- if (evt instanceof SslHandshakeCompletionEvent &&
+- ((SslHandshakeCompletionEvent) evt).cause() != null) {
+- ((SslHandshakeCompletionEvent) evt).cause().printStackTrace();
+- }
+- ctx.fireUserEventTriggered(evt);
+- }
+- });
+- }
+- }).connect(sc.localAddress());
+- cc = future.syncUninterruptibly().channel();
+-
+- assertTrue(clientSslHandler.handshakeFuture().await().isSuccess());
+- assertTrue(serverSslHandler.handshakeFuture().await().isSuccess());
+- } finally {
+- if (cc != null) {
+- cc.close().syncUninterruptibly();
+- }
+- if (sc != null) {
+- sc.close().syncUninterruptibly();
+- }
+- group.shutdownGracefully();
+- ReferenceCountUtil.release(sslClientCtx);
+- }
+- }
+-}
+diff --git a/transport-blockhound-tests/src/test/resources/io/netty/util/internal/localhost_server.key b/transport-blockhound-tests/src/test/resources/io/netty/util/internal/localhost_server.key
+deleted file mode 100644
+index 9aa6611400..0000000000
+--- a/transport-blockhound-tests/src/test/resources/io/netty/util/internal/localhost_server.key
++++ /dev/null
+@@ -1,28 +0,0 @@
+------BEGIN PRIVATE KEY-----
+-MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDYrLtMlZzoe2BP
+-iCURF3So5XNLfsOLcAVERXXjnxqX6Mex55WdJiy6uWTFKbRHWJdbWELdZxVl5+GX
+-pMv3OdkKZt+19ZdSfByv6bB5RNdZOEGnKOHSY2XdnzYnF5JBaWEx0fvtvIPZOUlW
+-DWgsQzJk1UQhu+XnBc7P1hHYNvwsVNOR+HD9LGebDy+UcfiL34XwAyBdHUsbcIr8
+-hltABcj6vNbqOLndpU86DxU9z9b1PDmkFVfisElhpDEhpxmTCwI22Us1GC8D81LM
+-ZzMlbWSzTfNPEuqNzJYGiFt/XPwPkPPyVvti0XWPBQpwzJFFUX5xKsOGERolELRT
+-0yNQYznFAgMBAAECggEAOFR/xSNITbB1k3ejm1PrwlUUqlXkZIXU+LDOO0UL1t5v
+-vDKm1Not2sWECzYSZlID132UtJauG3YzUgdH95gUcv3XvyiAFLOriZhJht181vcn
+-KlwYiWfJ/dn8bCFWpqbM2/TpeB8AcCLSjAqkQI2ftlMziUmeNXdvEt1mej2hRay1
+-ULfoxlC0mftNRQptD5gBFzrc47O4mVpVEQt4yS3Qyzp2/9ds9UkhaCIFpXPVCalZ
+-ds7R+bDDP+wiYTkUcd8fvelaMkD3Wcy8DedGRShhILZvBYTDdWcpJ7+e5EkNlEq4
+-+Ys4Y/u6aFDJD53g3zCaJhatmdAZcct2MMmWH1vewQKBgQD3Y2S245cad1D9AqYD
+-ChZGp95EfRo3EzXk4VkE50bjZXjHq9fD8T0CWEZGWQZrXJCR+vBpEURy0mrPD8se
+-QQ0Q5+I27RadtfPnMd6ry9nDGMPxyd/10vzU6LazzLNE+uf9ljF1RHZu1iDAvInR
+-r1cQGbn/wKBF6BurPPIXABZEuQKBgQDgN6JHbIfDzHKhwEoUTvRrYJsTXqplD+h0
+-Whg+kSQyhtKdlpINFOoEj8FUNJvTjG8les1aoajyWIqikVdvHto/mrxrSIeRkEmt
+-X+KG+5ld2n466tzv1DmVcIGXSrBrH3lA0i6R8Ly26FLSqw0Z12fx5GUUa1qaVRqo
+-rwcrIZovbQKBgHa2mojs9AC+Sv3uvG1u9LuZKJ7jDaZqMI2R2d7xgOH0Op5Ohy6+
+-39D1PVvasqroc3Op4J36rEcRVDHi2Uy+WJ/JNpO2+AhcXRuPodP88ZWel8C6aB+V
+-zL/6oFntnAU5BgR5g2hLny2W0YbLsrMNmhDe15O0AvUo6cYla+K/pu/5AoGACr/g
+-EdiMMcDthf+4DX0zjqpVBPq25J18oYdoPierOpjoJBIB8oqcJZfWxvi2t8+1zHA0
+-xDGX7fZ8vwqEzJkIEaCTg/k4NqxaO+uq6pnJYoyFHMIB0aW1FQsNy3kTOC+MGqV5
+-Ahoukf5VajA1MpX3L8upZO84qsmFu6yYhWLZB4kCgYBlgSD5G4q6rX4ELa3XG61h
+-fDtu75IYEsjWm4vgJzHjeYT2xPIm9OFFYXjPghto0f1oH37ODD3DoXmsnmddgpmn
+-tH7aRWWHsSpB5zVgftV4urNCIsm87LWw8mvUGgCwYV1CtCX8warKokfeoA2ltz4u
+-oeuUzo98hN+aKRU5RO6Bmg==
+------END PRIVATE KEY-----
+diff --git a/transport-blockhound-tests/src/test/resources/io/netty/util/internal/localhost_server.pem b/transport-blockhound-tests/src/test/resources/io/netty/util/internal/localhost_server.pem
+deleted file mode 100644
+index 70759b29e5..0000000000
+--- a/transport-blockhound-tests/src/test/resources/io/netty/util/internal/localhost_server.pem
++++ /dev/null
+@@ -1,17 +0,0 @@
+------BEGIN CERTIFICATE-----
+-MIICozCCAYsCAnS/MA0GCSqGSIb3DQEBDQUAMBgxFjAUBgNVBAMTDU5ldHR5VGVz
+-dFJvb3QwIBcNMTcwMjE3MDMzMzQ0WhgPMjExNzAxMjQwMzMzNDRaMBQxEjAQBgNV
+-BAMTCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANis
+-u0yVnOh7YE+IJREXdKjlc0t+w4twBURFdeOfGpfox7HnlZ0mLLq5ZMUptEdYl1tY
+-Qt1nFWXn4Zeky/c52Qpm37X1l1J8HK/psHlE11k4Qaco4dJjZd2fNicXkkFpYTHR
+-++28g9k5SVYNaCxDMmTVRCG75ecFzs/WEdg2/CxU05H4cP0sZ5sPL5Rx+IvfhfAD
+-IF0dSxtwivyGW0AFyPq81uo4ud2lTzoPFT3P1vU8OaQVV+KwSWGkMSGnGZMLAjbZ
+-SzUYLwPzUsxnMyVtZLNN808S6o3MlgaIW39c/A+Q8/JW+2LRdY8FCnDMkUVRfnEq
+-w4YRGiUQtFPTI1BjOcUCAwEAATANBgkqhkiG9w0BAQ0FAAOCAQEAQNXnwE2MJFy5
+-ti07xyi8h/mY0Kl1dwZUqx4F9D9eoxLCq2/p3h/Z18AlOmjdW06pvC2sGtQtyEqL
+-YjuQFbMjXRo9c+6+d+xwdDKTu7+XOTHvznJ8xJpKnFOlohGq/n3efBIJSsaeasTU
+-slFzmdKYABDZzbsQ4X6YCIOF4XVdEQqmXpS+uEbn5C2sVtG+LXI8srmkVGpCcRew
+-SuTGanwxLparhBBeN1ARjKzNxXUWuK2UKZ9p8c7n7TXGhd12ZNTcLhk4rCnOFq1J
+-ySFvP5YL2q29fpEt+Tq0zm3V7An2qtaNDp26cEdevtKPjRyOLkCJx8OlZxc9DZvJ
+-HjalFDoRUw==
+------END CERTIFICATE-----
+diff --git a/transport-blockhound-tests/src/test/resources/io/netty/util/internal/mutual_auth_ca.pem b/transport-blockhound-tests/src/test/resources/io/netty/util/internal/mutual_auth_ca.pem
+deleted file mode 100644
+index 9c9241bc65..0000000000
+--- a/transport-blockhound-tests/src/test/resources/io/netty/util/internal/mutual_auth_ca.pem
++++ /dev/null
+@@ -1,19 +0,0 @@
+------BEGIN CERTIFICATE-----
+-MIIDLDCCAhSgAwIBAgIJAO1m5pioZhLLMA0GCSqGSIb3DQEBDQUAMBgxFjAUBgNV
+-BAMTDU5ldHR5VGVzdFJvb3QwHhcNMTcwMjE3MDMzMzQ0WhcNMTcwMzE5MDMzMzQ0
+-WjAYMRYwFAYDVQQDEw1OZXR0eVRlc3RSb290MIIBIjANBgkqhkiG9w0BAQEFAAOC
+-AQ8AMIIBCgKCAQEAnC7Y/p/TSWI1KxBKETfFKaRWCPEkoYn5G973WbCF0VDT90PX
+-xK6yHvhqNdDQZPmddgfDAQfjekHeeIFkjCKlvQu0js0G4Bubz4NffNumd/Mgsix8
+-SWJ13lPk+Ly4PDv0bK1zB6BxP1qQm1qxVwsPy9zNP8ylJrM0Div4TXHmnWOfc0JD
+-4/XPpfeUHH1tt/GMtsS2Gx6EpTVPD2w7LDKUza1/rQ7d9sqmFpgsNcI9Db/sAtFP
+-lK2iJku5WIXQkmHimn4bqZ9wkiXJ85pm5ggGQqGMPSbe+2Lh24AvZMIBiwPbkjEU
+-EDFXEJfKOC3Dl71JgWOthtHZ9vcCRDQ3Sky6AQIDAQABo3kwdzAdBgNVHQ4EFgQU
+-qT+cH8qrebiVPpKCBQDB6At2iOAwSAYDVR0jBEEwP4AUqT+cH8qrebiVPpKCBQDB
+-6At2iOChHKQaMBgxFjAUBgNVBAMTDU5ldHR5VGVzdFJvb3SCCQDtZuaYqGYSyzAM
+-BgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBDQUAA4IBAQCEemXTIew4pR2cHEFpVsW2
+-bLHXLAnC23wBMT46D3tqyxscukMYjFuWosCdEsgRW8d50BXy9o4dHWeg94+aDo3A
+-DX4OTRN/veQGIG7dgM6poDzFuVJlSN0ubKKg6gpDD60IhopZpMviFAOsmzr7OXwS
+-9hjbTqUWujMIEHQ95sPlQFdSaavYSFfqhSltWmVCPSbArxrw0lZ2QcnUqGN47EFp
+-whc5wFB+rSw/ojU1jBLMvgvgzf/8V8zr1IBTDSiHNlknGqGpOOaookzUh95YRiAT
+-hH82y9bBeflqroOeztqMpONpWoZjlz0sWbJNvXztXINL7LaNmVYOcoUrCcxPS54T
+------END CERTIFICATE-----
+--
+2.26.2
+
diff --git a/0002-Remove-NPN-ALPN.patch b/0002-Remove-NPN-ALPN.patch
deleted file mode 100644
index 73749cc..0000000
--- a/0002-Remove-NPN-ALPN.patch
+++ /dev/null
@@ -1,884 +0,0 @@
-From cfb6f2a620525a94d6964c287792f2645bff4f4a Mon Sep 17 00:00:00 2001
-From: Severin Gehwolf <sgehwolf(a)redhat.com>
-Date: Thu, 20 Oct 2016 16:18:10 +0200
-Subject: [PATCH 2/2] Remove NPN ALPN
-
----
- .../ssl/JdkAlpnApplicationProtocolNegotiator.java | 120 ---------
- .../io/netty/handler/ssl/JdkAlpnSslEngine.java | 124 ----------
- .../ssl/JdkNpnApplicationProtocolNegotiator.java | 120 ---------
- .../java/io/netty/handler/ssl/JdkNpnSslEngine.java | 122 ---------
- .../java/io/netty/handler/ssl/JdkSslContext.java | 44 ----
- .../io/netty/handler/ssl/JdkSslEngineTest.java | 273 ---------------------
- 6 files changed, 803 deletions(-)
- delete mode 100644 handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java
- delete mode 100644 handler/src/main/java/io/netty/handler/ssl/JdkAlpnSslEngine.java
- delete mode 100644 handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java
- delete mode 100644 handler/src/main/java/io/netty/handler/ssl/JdkNpnSslEngine.java
-
-diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java b/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java
-deleted file mode 100644
-index aaaf5b7..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java
-+++ /dev/null
-@@ -1,120 +0,0 @@
--/*
-- * Copyright 2014 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
--
--import javax.net.ssl.SSLEngine;
--
--/**
-- * The {@link JdkApplicationProtocolNegotiator} to use if you need ALPN and are using {@link SslProvider#JDK}.
-- */
--public final class JdkAlpnApplicationProtocolNegotiator extends JdkBaseApplicationProtocolNegotiator {
-- private static final SslEngineWrapperFactory ALPN_WRAPPER = new SslEngineWrapperFactory() {
-- {
-- if (!JdkAlpnSslEngine.isAvailable()) {
-- throw new RuntimeException("ALPN unsupported. Is your classpatch configured correctly?"
-- + " See http://www.eclipse.org/jetty/documentation/current/alpn-chapter.html#alpn...");
-- }
-- }
--
-- @Override
-- public SSLEngine wrapSslEngine(SSLEngine engine, JdkApplicationProtocolNegotiator applicationNegotiator,
-- boolean isServer) {
-- return new JdkAlpnSslEngine(engine, applicationNegotiator, isServer);
-- }
-- };
--
-- /**
-- * Create a new instance.
-- * @param protocols The order of iteration determines the preference of support for protocols.
-- */
-- public JdkAlpnApplicationProtocolNegotiator(Iterable<String> protocols) {
-- this(false, protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param protocols The order of iteration determines the preference of support for protocols.
-- */
-- public JdkAlpnApplicationProtocolNegotiator(String... protocols) {
-- this(false, protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param failIfNoCommonProtocols Fail with a fatal alert if not common protocols are detected.
-- * @param protocols The order of iteration determines the preference of support for protocols.
-- */
-- public JdkAlpnApplicationProtocolNegotiator(boolean failIfNoCommonProtocols, Iterable<String> protocols) {
-- this(failIfNoCommonProtocols, failIfNoCommonProtocols, protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param failIfNoCommonProtocols Fail with a fatal alert if not common protocols are detected.
-- * @param protocols The order of iteration determines the preference of support for protocols.
-- */
-- public JdkAlpnApplicationProtocolNegotiator(boolean failIfNoCommonProtocols, String... protocols) {
-- this(failIfNoCommonProtocols, failIfNoCommonProtocols, protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param clientFailIfNoCommonProtocols Client side fail with a fatal alert if not common protocols are detected.
-- * @param serverFailIfNoCommonProtocols Server side fail with a fatal alert if not common protocols are detected.
-- * @param protocols The order of iteration determines the preference of support for protocols.
-- */
-- public JdkAlpnApplicationProtocolNegotiator(boolean clientFailIfNoCommonProtocols,
-- boolean serverFailIfNoCommonProtocols, Iterable<String> protocols) {
-- this(serverFailIfNoCommonProtocols ? FAIL_SELECTOR_FACTORY : NO_FAIL_SELECTOR_FACTORY,
-- clientFailIfNoCommonProtocols ? FAIL_SELECTION_LISTENER_FACTORY : NO_FAIL_SELECTION_LISTENER_FACTORY,
-- protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param clientFailIfNoCommonProtocols Client side fail with a fatal alert if not common protocols are detected.
-- * @param serverFailIfNoCommonProtocols Server side fail with a fatal alert if not common protocols are detected.
-- * @param protocols The order of iteration determines the preference of support for protocols.
-- */
-- public JdkAlpnApplicationProtocolNegotiator(boolean clientFailIfNoCommonProtocols,
-- boolean serverFailIfNoCommonProtocols, String... protocols) {
-- this(serverFailIfNoCommonProtocols ? FAIL_SELECTOR_FACTORY : NO_FAIL_SELECTOR_FACTORY,
-- clientFailIfNoCommonProtocols ? FAIL_SELECTION_LISTENER_FACTORY : NO_FAIL_SELECTION_LISTENER_FACTORY,
-- protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param selectorFactory The factory which provides classes responsible for selecting the protocol.
-- * @param listenerFactory The factory which provides to be notified of which protocol was selected.
-- * @param protocols The order of iteration determines the preference of support for protocols.
-- */
-- public JdkAlpnApplicationProtocolNegotiator(ProtocolSelectorFactory selectorFactory,
-- ProtocolSelectionListenerFactory listenerFactory, Iterable<String> protocols) {
-- super(ALPN_WRAPPER, selectorFactory, listenerFactory, protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param selectorFactory The factory which provides classes responsible for selecting the protocol.
-- * @param listenerFactory The factory which provides to be notified of which protocol was selected.
-- * @param protocols The order of iteration determines the preference of support for protocols.
-- */
-- public JdkAlpnApplicationProtocolNegotiator(ProtocolSelectorFactory selectorFactory,
-- ProtocolSelectionListenerFactory listenerFactory, String... protocols) {
-- super(ALPN_WRAPPER, selectorFactory, listenerFactory, protocols);
-- }
--}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnSslEngine.java b/handler/src/main/java/io/netty/handler/ssl/JdkAlpnSslEngine.java
-deleted file mode 100644
-index bdf3aca..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnSslEngine.java
-+++ /dev/null
-@@ -1,124 +0,0 @@
--/*
-- * Copyright 2014 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
--
--import static io.netty.util.internal.ObjectUtil.checkNotNull;
--import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectionListener;
--import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector;
--
--import java.util.LinkedHashSet;
--import java.util.List;
--
--import javax.net.ssl.SSLEngine;
--import javax.net.ssl.SSLException;
--import javax.net.ssl.SSLHandshakeException;
--
--import org.eclipse.jetty.alpn.ALPN;
--import org.eclipse.jetty.alpn.ALPN.ClientProvider;
--import org.eclipse.jetty.alpn.ALPN.ServerProvider;
--
--final class JdkAlpnSslEngine extends JdkSslEngine {
-- private static boolean available;
--
-- static boolean isAvailable() {
-- updateAvailability();
-- return available;
-- }
--
-- private static void updateAvailability() {
-- if (available) {
-- return;
-- }
--
-- try {
-- // Always use bootstrap class loader.
-- Class.forName("sun.security.ssl.ALPNExtension", true, null);
-- available = true;
-- } catch (Exception ignore) {
-- // alpn-boot was not loaded.
-- }
-- }
--
-- JdkAlpnSslEngine(SSLEngine engine, final JdkApplicationProtocolNegotiator applicationNegotiator, boolean server) {
-- super(engine);
-- checkNotNull(applicationNegotiator, "applicationNegotiator");
--
-- if (server) {
-- final ProtocolSelector protocolSelector = checkNotNull(applicationNegotiator.protocolSelectorFactory()
-- .newSelector(this, new LinkedHashSet<String>(applicationNegotiator.protocols())),
-- "protocolSelector");
-- ALPN.put(engine, new ServerProvider() {
-- @Override
-- public String select(List<String> protocols) throws SSLException {
-- try {
-- return protocolSelector.select(protocols);
-- } catch (SSLHandshakeException e) {
-- throw e;
-- } catch (Throwable t) {
-- SSLHandshakeException e = new SSLHandshakeException(t.getMessage());
-- e.initCause(t);
-- throw e;
-- }
-- }
--
-- @Override
-- public void unsupported() {
-- protocolSelector.unsupported();
-- }
-- });
-- } else {
-- final ProtocolSelectionListener protocolListener = checkNotNull(applicationNegotiator
-- .protocolListenerFactory().newListener(this, applicationNegotiator.protocols()),
-- "protocolListener");
-- ALPN.put(engine, new ClientProvider() {
-- @Override
-- public List<String> protocols() {
-- return applicationNegotiator.protocols();
-- }
--
-- @Override
-- public void selected(String protocol) throws SSLException {
-- try {
-- protocolListener.selected(protocol);
-- } catch (SSLHandshakeException e) {
-- throw e;
-- } catch (Throwable t) {
-- SSLHandshakeException e = new SSLHandshakeException(t.getMessage());
-- e.initCause(t);
-- throw e;
-- }
-- }
--
-- @Override
-- public void unsupported() {
-- protocolListener.unsupported();
-- }
-- });
-- }
-- }
--
-- @Override
-- public void closeInbound() throws SSLException {
-- ALPN.remove(getWrappedEngine());
-- super.closeInbound();
-- }
--
-- @Override
-- public void closeOutbound() {
-- ALPN.remove(getWrappedEngine());
-- super.closeOutbound();
-- }
--}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java b/handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java
-deleted file mode 100644
-index c893f05..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java
-+++ /dev/null
-@@ -1,120 +0,0 @@
--/*
-- * Copyright 2014 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
--
--import javax.net.ssl.SSLEngine;
--
--/**
-- * The {@link JdkApplicationProtocolNegotiator} to use if you need NPN and are using {@link SslProvider#JDK}.
-- */
--public final class JdkNpnApplicationProtocolNegotiator extends JdkBaseApplicationProtocolNegotiator {
-- private static final SslEngineWrapperFactory NPN_WRAPPER = new SslEngineWrapperFactory() {
-- {
-- if (!JdkNpnSslEngine.isAvailable()) {
-- throw new RuntimeException("NPN unsupported. Is your classpatch configured correctly?"
-- + " See http://www.eclipse.org/jetty/documentation/current/npn-chapter.html#npn-s...");
-- }
-- }
--
-- @Override
-- public SSLEngine wrapSslEngine(SSLEngine engine, JdkApplicationProtocolNegotiator applicationNegotiator,
-- boolean isServer) {
-- return new JdkNpnSslEngine(engine, applicationNegotiator, isServer);
-- }
-- };
--
-- /**
-- * Create a new instance.
-- * @param protocols The order of iteration determines the preference of support for protocols.
-- */
-- public JdkNpnApplicationProtocolNegotiator(Iterable<String> protocols) {
-- this(false, protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param protocols The order of iteration determines the preference of support for protocols.
-- */
-- public JdkNpnApplicationProtocolNegotiator(String... protocols) {
-- this(false, protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param failIfNoCommonProtocols Fail with a fatal alert if not common protocols are detected.
-- * @param protocols The order of iteration determines the preference of support for protocols.
-- */
-- public JdkNpnApplicationProtocolNegotiator(boolean failIfNoCommonProtocols, Iterable<String> protocols) {
-- this(failIfNoCommonProtocols, failIfNoCommonProtocols, protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param failIfNoCommonProtocols Fail with a fatal alert if not common protocols are detected.
-- * @param protocols The order of iteration determines the preference of support for protocols.
-- */
-- public JdkNpnApplicationProtocolNegotiator(boolean failIfNoCommonProtocols, String... protocols) {
-- this(failIfNoCommonProtocols, failIfNoCommonProtocols, protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param clientFailIfNoCommonProtocols Client side fail with a fatal alert if not common protocols are detected.
-- * @param serverFailIfNoCommonProtocols Server side fail with a fatal alert if not common protocols are detected.
-- * @param protocols The order of iteration determines the preference of support for protocols.
-- */
-- public JdkNpnApplicationProtocolNegotiator(boolean clientFailIfNoCommonProtocols,
-- boolean serverFailIfNoCommonProtocols, Iterable<String> protocols) {
-- this(clientFailIfNoCommonProtocols ? FAIL_SELECTOR_FACTORY : NO_FAIL_SELECTOR_FACTORY,
-- serverFailIfNoCommonProtocols ? FAIL_SELECTION_LISTENER_FACTORY : NO_FAIL_SELECTION_LISTENER_FACTORY,
-- protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param clientFailIfNoCommonProtocols Client side fail with a fatal alert if not common protocols are detected.
-- * @param serverFailIfNoCommonProtocols Server side fail with a fatal alert if not common protocols are detected.
-- * @param protocols The order of iteration determines the preference of support for protocols.
-- */
-- public JdkNpnApplicationProtocolNegotiator(boolean clientFailIfNoCommonProtocols,
-- boolean serverFailIfNoCommonProtocols, String... protocols) {
-- this(clientFailIfNoCommonProtocols ? FAIL_SELECTOR_FACTORY : NO_FAIL_SELECTOR_FACTORY,
-- serverFailIfNoCommonProtocols ? FAIL_SELECTION_LISTENER_FACTORY : NO_FAIL_SELECTION_LISTENER_FACTORY,
-- protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param selectorFactory The factory which provides classes responsible for selecting the protocol.
-- * @param listenerFactory The factory which provides to be notified of which protocol was selected.
-- * @param protocols The order of iteration determines the preference of support for protocols.
-- */
-- public JdkNpnApplicationProtocolNegotiator(ProtocolSelectorFactory selectorFactory,
-- ProtocolSelectionListenerFactory listenerFactory, Iterable<String> protocols) {
-- super(NPN_WRAPPER, selectorFactory, listenerFactory, protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param selectorFactory The factory which provides classes responsible for selecting the protocol.
-- * @param listenerFactory The factory which provides to be notified of which protocol was selected.
-- * @param protocols The order of iteration determines the preference of support for protocols.
-- */
-- public JdkNpnApplicationProtocolNegotiator(ProtocolSelectorFactory selectorFactory,
-- ProtocolSelectionListenerFactory listenerFactory, String... protocols) {
-- super(NPN_WRAPPER, selectorFactory, listenerFactory, protocols);
-- }
--}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkNpnSslEngine.java b/handler/src/main/java/io/netty/handler/ssl/JdkNpnSslEngine.java
-deleted file mode 100644
-index 422727a..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/JdkNpnSslEngine.java
-+++ /dev/null
-@@ -1,122 +0,0 @@
--/*
-- * Copyright 2014 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--
--package io.netty.handler.ssl;
--
--import static io.netty.util.internal.ObjectUtil.checkNotNull;
--import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectionListener;
--import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector;
--import io.netty.util.internal.PlatformDependent;
--
--import java.util.LinkedHashSet;
--import java.util.List;
--
--import javax.net.ssl.SSLEngine;
--import javax.net.ssl.SSLException;
--
--import org.eclipse.jetty.npn.NextProtoNego;
--import org.eclipse.jetty.npn.NextProtoNego.ClientProvider;
--import org.eclipse.jetty.npn.NextProtoNego.ServerProvider;
--
--final class JdkNpnSslEngine extends JdkSslEngine {
-- private static boolean available;
--
-- static boolean isAvailable() {
-- updateAvailability();
-- return available;
-- }
--
-- private static void updateAvailability() {
-- if (available) {
-- return;
-- }
-- try {
-- // Always use bootstrap class loader.
-- Class.forName("sun.security.ssl.NextProtoNegoExtension", true, null);
-- available = true;
-- } catch (Exception ignore) {
-- // npn-boot was not loaded.
-- }
-- }
--
-- JdkNpnSslEngine(SSLEngine engine, final JdkApplicationProtocolNegotiator applicationNegotiator, boolean server) {
-- super(engine);
-- checkNotNull(applicationNegotiator, "applicationNegotiator");
--
-- if (server) {
-- final ProtocolSelectionListener protocolListener = checkNotNull(applicationNegotiator
-- .protocolListenerFactory().newListener(this, applicationNegotiator.protocols()),
-- "protocolListener");
-- NextProtoNego.put(engine, new ServerProvider() {
-- @Override
-- public void unsupported() {
-- protocolListener.unsupported();
-- }
--
-- @Override
-- public List<String> protocols() {
-- return applicationNegotiator.protocols();
-- }
--
-- @Override
-- public void protocolSelected(String protocol) {
-- try {
-- protocolListener.selected(protocol);
-- } catch (Throwable t) {
-- PlatformDependent.throwException(t);
-- }
-- }
-- });
-- } else {
-- final ProtocolSelector protocolSelector = checkNotNull(applicationNegotiator.protocolSelectorFactory()
-- .newSelector(this, new LinkedHashSet<String>(applicationNegotiator.protocols())),
-- "protocolSelector");
-- NextProtoNego.put(engine, new ClientProvider() {
-- @Override
-- public boolean supports() {
-- return true;
-- }
--
-- @Override
-- public void unsupported() {
-- protocolSelector.unsupported();
-- }
--
-- @Override
-- public String selectProtocol(List<String> protocols) {
-- try {
-- return protocolSelector.select(protocols);
-- } catch (Throwable t) {
-- PlatformDependent.throwException(t);
-- return null;
-- }
-- }
-- });
-- }
-- }
--
-- @Override
-- public void closeInbound() throws SSLException {
-- NextProtoNego.remove(getWrappedEngine());
-- super.closeInbound();
-- }
--
-- @Override
-- public void closeOutbound() {
-- NextProtoNego.remove(getWrappedEngine());
-- super.closeOutbound();
-- }
--}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkSslContext.java b/handler/src/main/java/io/netty/handler/ssl/JdkSslContext.java
-index 0a120eb..cdad232 100644
---- a/handler/src/main/java/io/netty/handler/ssl/JdkSslContext.java
-+++ b/handler/src/main/java/io/netty/handler/ssl/JdkSslContext.java
-@@ -270,50 +270,6 @@ public class JdkSslContext extends SslContext {
- switch(config.protocol()) {
- case NONE:
- return JdkDefaultApplicationProtocolNegotiator.INSTANCE;
-- case ALPN:
-- if (isServer) {
-- switch(config.selectorFailureBehavior()) {
-- case FATAL_ALERT:
-- return new JdkAlpnApplicationProtocolNegotiator(true, config.supportedProtocols());
-- case NO_ADVERTISE:
-- return new JdkAlpnApplicationProtocolNegotiator(false, config.supportedProtocols());
-- default:
-- throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ")
-- .append(config.selectorFailureBehavior()).append(" failure behavior").toString());
-- }
-- } else {
-- switch(config.selectedListenerFailureBehavior()) {
-- case ACCEPT:
-- return new JdkAlpnApplicationProtocolNegotiator(false, config.supportedProtocols());
-- case FATAL_ALERT:
-- return new JdkAlpnApplicationProtocolNegotiator(true, config.supportedProtocols());
-- default:
-- throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ")
-- .append(config.selectedListenerFailureBehavior()).append(" failure behavior").toString());
-- }
-- }
-- case NPN:
-- if (isServer) {
-- switch(config.selectedListenerFailureBehavior()) {
-- case ACCEPT:
-- return new JdkNpnApplicationProtocolNegotiator(false, config.supportedProtocols());
-- case FATAL_ALERT:
-- return new JdkNpnApplicationProtocolNegotiator(true, config.supportedProtocols());
-- default:
-- throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ")
-- .append(config.selectedListenerFailureBehavior()).append(" failure behavior").toString());
-- }
-- } else {
-- switch(config.selectorFailureBehavior()) {
-- case FATAL_ALERT:
-- return new JdkNpnApplicationProtocolNegotiator(true, config.supportedProtocols());
-- case NO_ADVERTISE:
-- return new JdkNpnApplicationProtocolNegotiator(false, config.supportedProtocols());
-- default:
-- throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ")
-- .append(config.selectorFailureBehavior()).append(" failure behavior").toString());
-- }
-- }
- default:
- throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ")
- .append(config.protocol()).append(" protocol").toString());
-diff --git a/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java b/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java
-index 9a57230..090f996 100644
---- a/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java
-+++ b/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java
-@@ -15,262 +15,15 @@
- */
- package io.netty.handler.ssl;
-
--import io.netty.handler.ssl.ApplicationProtocolConfig.Protocol;
--import io.netty.handler.ssl.ApplicationProtocolConfig.SelectedListenerFailureBehavior;
--import io.netty.handler.ssl.ApplicationProtocolConfig.SelectorFailureBehavior;
--import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector;
--import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectorFactory;
--import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
--import io.netty.handler.ssl.util.SelfSignedCertificate;
- import org.junit.Test;
-
--import javax.net.ssl.SSLEngine;
--import javax.net.ssl.SSLHandshakeException;
--import java.util.List;
--import java.util.Set;
--import java.util.concurrent.TimeUnit;
--
--import static org.junit.Assert.assertNull;
--import static org.junit.Assert.assertTrue;
--import static org.junit.Assume.assumeNoException;
--
- public class JdkSslEngineTest extends SSLEngineTest {
-- private static final String PREFERRED_APPLICATION_LEVEL_PROTOCOL = "my-protocol-http2";
-- private static final String FALLBACK_APPLICATION_LEVEL_PROTOCOL = "my-protocol-http1_1";
-- private static final String APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE = "my-protocol-FOO";
--
-- @Test
-- public void testNpn() throws Exception {
-- try {
-- // Typical code will not have to check this, but will get a initialization error on class load.
-- // Check in this test just in case we have multiple tests that just the class and we already ignored the
-- // initialization error.
-- if (!JdkNpnSslEngine.isAvailable()) {
-- throw tlsExtensionNotFound(Protocol.NPN);
-- }
-- ApplicationProtocolConfig apn = failingNegotiator(Protocol.NPN,
-- PREFERRED_APPLICATION_LEVEL_PROTOCOL);
-- setupHandlers(apn);
-- runTest();
-- } catch (SkipTestException e) {
-- // NPN availability is dependent on the java version. If NPN is not available because of
-- // java version incompatibility don't fail the test, but instead just skip the test
-- assumeNoException(e);
-- }
-- }
--
-- @Test
-- public void testNpnNoCompatibleProtocolsNoHandshakeFailure() throws Exception {
-- try {
-- // Typical code will not have to check this, but will get a initialization error on class load.
-- // Check in this test just in case we have multiple tests that just the class and we already ignored the
-- // initialization error.
-- if (!JdkNpnSslEngine.isAvailable()) {
-- throw tlsExtensionNotFound(Protocol.NPN);
-- }
-- ApplicationProtocolConfig clientApn = acceptingNegotiator(Protocol.NPN,
-- PREFERRED_APPLICATION_LEVEL_PROTOCOL);
-- ApplicationProtocolConfig serverApn = acceptingNegotiator(Protocol.NPN,
-- APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE);
-- setupHandlers(serverApn, clientApn);
-- runTest(null);
-- } catch (SkipTestException e) {
-- // ALPN availability is dependent on the java version. If ALPN is not available because of
-- // java version incompatibility don't fail the test, but instead just skip the test
-- assumeNoException(e);
-- }
-- }
--
-- @Test
-- public void testNpnNoCompatibleProtocolsClientHandshakeFailure() throws Exception {
-- try {
-- // Typical code will not have to check this, but will get a initialization error on class load.
-- // Check in this test just in case we have multiple tests that just the class and we already ignored the
-- // initialization error.
-- if (!JdkNpnSslEngine.isAvailable()) {
-- throw tlsExtensionNotFound(Protocol.NPN);
-- }
-- ApplicationProtocolConfig clientApn = failingNegotiator(Protocol.NPN,
-- PREFERRED_APPLICATION_LEVEL_PROTOCOL);
-- ApplicationProtocolConfig serverApn = acceptingNegotiator(Protocol.NPN,
-- APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE);
-- setupHandlers(serverApn, clientApn);
-- assertTrue(clientLatch.await(2, TimeUnit.SECONDS));
-- assertTrue(clientException instanceof SSLHandshakeException);
-- } catch (SkipTestException e) {
-- // NPN availability is dependent on the java version. If NPN is not available because of
-- // java version incompatibility don't fail the test, but instead just skip the test
-- assumeNoException(e);
-- }
-- }
--
-- @Test
-- public void testNpnNoCompatibleProtocolsServerHandshakeFailure() throws Exception {
-- try {
-- // Typical code will not have to check this, but will get a initialization error on class load.
-- // Check in this test just in case we have multiple tests that just the class and we already ignored the
-- // initialization error.
-- if (!JdkNpnSslEngine.isAvailable()) {
-- throw tlsExtensionNotFound(Protocol.NPN);
-- }
-- ApplicationProtocolConfig clientApn = acceptingNegotiator(Protocol.NPN,
-- PREFERRED_APPLICATION_LEVEL_PROTOCOL);
-- ApplicationProtocolConfig serverApn = failingNegotiator(Protocol.NPN,
-- APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE);
-- setupHandlers(serverApn, clientApn);
-- assertTrue(serverLatch.await(2, TimeUnit.SECONDS));
-- assertTrue(serverException instanceof SSLHandshakeException);
-- } catch (SkipTestException e) {
-- // NPN availability is dependent on the java version. If NPN is not available because of
-- // java version incompatibility don't fail the test, but instead just skip the test
-- assumeNoException(e);
-- }
-- }
--
-- @Test
-- public void testAlpn() throws Exception {
-- try {
-- // Typical code will not have to check this, but will get a initialization error on class load.
-- // Check in this test just in case we have multiple tests that just the class and we already ignored the
-- // initialization error.
-- if (!JdkAlpnSslEngine.isAvailable()) {
-- throw tlsExtensionNotFound(Protocol.ALPN);
-- }
-- ApplicationProtocolConfig apn = failingNegotiator(Protocol.ALPN,
-- PREFERRED_APPLICATION_LEVEL_PROTOCOL);
-- setupHandlers(apn);
-- runTest();
-- } catch (SkipTestException e) {
-- // ALPN availability is dependent on the java version. If ALPN is not available because of
-- // java version incompatibility don't fail the test, but instead just skip the test
-- assumeNoException(e);
-- }
-- }
--
-- @Test
-- public void testAlpnNoCompatibleProtocolsNoHandshakeFailure() throws Exception {
-- try {
-- // Typical code will not have to check this, but will get a initialization error on class load.
-- // Check in this test just in case we have multiple tests that just the class and we already ignored the
-- // initialization error.
-- if (!JdkAlpnSslEngine.isAvailable()) {
-- throw tlsExtensionNotFound(Protocol.ALPN);
-- }
-- ApplicationProtocolConfig clientApn = acceptingNegotiator(Protocol.ALPN,
-- PREFERRED_APPLICATION_LEVEL_PROTOCOL);
-- ApplicationProtocolConfig serverApn = acceptingNegotiator(Protocol.ALPN,
-- APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE);
-- setupHandlers(serverApn, clientApn);
-- runTest(null);
-- } catch (SkipTestException e) {
-- // ALPN availability is dependent on the java version. If ALPN is not available because of
-- // java version incompatibility don't fail the test, but instead just skip the test
-- assumeNoException(e);
-- }
-- }
--
-- @Test
-- public void testAlpnNoCompatibleProtocolsServerHandshakeFailure() throws Exception {
-- try {
-- // Typical code will not have to check this, but will get a initialization error on class load.
-- // Check in this test just in case we have multiple tests that just the class and we already ignored the
-- // initialization error.
-- if (!JdkAlpnSslEngine.isAvailable()) {
-- throw tlsExtensionNotFound(Protocol.ALPN);
-- }
-- ApplicationProtocolConfig clientApn = acceptingNegotiator(Protocol.ALPN,
-- PREFERRED_APPLICATION_LEVEL_PROTOCOL);
-- ApplicationProtocolConfig serverApn = failingNegotiator(Protocol.ALPN,
-- APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE);
-- setupHandlers(serverApn, clientApn);
-- assertTrue(serverLatch.await(2, TimeUnit.SECONDS));
-- assertTrue(serverException instanceof SSLHandshakeException);
-- } catch (SkipTestException e) {
-- // ALPN availability is dependent on the java version. If ALPN is not available because of
-- // java version incompatibility don't fail the test, but instead just skip the test
-- assumeNoException(e);
-- }
-- }
--
-- @Test
-- public void testAlpnCompatibleProtocolsDifferentClientOrder() throws Exception {
-- try {
-- // Typical code will not have to check this, but will get a initialization error on class load.
-- // Check in this test just in case we have multiple tests that just the class and we already ignored the
-- // initialization error.
-- if (!JdkAlpnSslEngine.isAvailable()) {
-- throw tlsExtensionNotFound(Protocol.ALPN);
-- }
-- // Even the preferred application protocol appears second in the client's list, it will be picked
-- // because it's the first one on server's list.
-- ApplicationProtocolConfig clientApn = acceptingNegotiator(Protocol.ALPN,
-- FALLBACK_APPLICATION_LEVEL_PROTOCOL, PREFERRED_APPLICATION_LEVEL_PROTOCOL);
-- ApplicationProtocolConfig serverApn = failingNegotiator(Protocol.ALPN,
-- PREFERRED_APPLICATION_LEVEL_PROTOCOL, FALLBACK_APPLICATION_LEVEL_PROTOCOL);
-- setupHandlers(serverApn, clientApn);
-- assertNull(serverException);
-- runTest(PREFERRED_APPLICATION_LEVEL_PROTOCOL);
-- } catch (SkipTestException e) {
-- // ALPN availability is dependent on the java version. If ALPN is not available because of
-- // java version incompatibility don't fail the test, but instead just skip the test
-- assumeNoException(e);
-- }
-- }
--
-- @Test
-- public void testAlpnNoCompatibleProtocolsClientHandshakeFailure() throws Exception {
-- try {
-- // Typical code will not have to check this, but will get a initialization error on class load.
-- // Check in this test just in case we have multiple tests that just the class and we already ignored the
-- // initialization error.
-- if (!JdkAlpnSslEngine.isAvailable()) {
-- throw tlsExtensionNotFound(Protocol.ALPN);
-- }
-- SelfSignedCertificate ssc = new SelfSignedCertificate();
-- JdkApplicationProtocolNegotiator clientApn = new JdkAlpnApplicationProtocolNegotiator(true, true,
-- PREFERRED_APPLICATION_LEVEL_PROTOCOL);
-- JdkApplicationProtocolNegotiator serverApn = new JdkAlpnApplicationProtocolNegotiator(
-- new ProtocolSelectorFactory() {
-- @Override
-- public ProtocolSelector newSelector(SSLEngine engine, Set<String> supportedProtocols) {
-- return new ProtocolSelector() {
-- @Override
-- public void unsupported() {
-- }
--
-- @Override
-- public String select(List<String> protocols) {
-- return APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE;
-- }
-- };
-- }
-- }, JdkBaseApplicationProtocolNegotiator.FAIL_SELECTION_LISTENER_FACTORY,
-- APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE);
--
-- SslContext serverSslCtx = new JdkSslServerContext(ssc.certificate(), ssc.privateKey(), null, null,
-- IdentityCipherSuiteFilter.INSTANCE, serverApn, 0, 0);
-- SslContext clientSslCtx = new JdkSslClientContext(null, InsecureTrustManagerFactory.INSTANCE, null,
-- IdentityCipherSuiteFilter.INSTANCE, clientApn, 0, 0);
--
-- setupHandlers(serverSslCtx, clientSslCtx);
-- assertTrue(clientLatch.await(2, TimeUnit.SECONDS));
-- assertTrue(clientException instanceof SSLHandshakeException);
-- } catch (SkipTestException e) {
-- // ALPN availability is dependent on the java version. If ALPN is not available because of
-- // java version incompatibility don't fail the test, but instead just skip the test
-- assumeNoException(e);
-- }
-- }
-
- @Test
- public void testEnablingAnAlreadyDisabledSslProtocol() throws Exception {
- testEnablingAnAlreadyDisabledSslProtocol(new String[]{}, new String[]{PROTOCOL_TLS_V1_2});
- }
-
-- private void runTest() throws Exception {
-- runTest(PREFERRED_APPLICATION_LEVEL_PROTOCOL);
-- }
--
- @Override
- protected SslProvider sslClientProvider() {
- return SslProvider.JDK;
-@@ -280,30 +33,4 @@ public class JdkSslEngineTest extends SSLEngineTest {
- protected SslProvider sslServerProvider() {
- return SslProvider.JDK;
- }
--
-- private ApplicationProtocolConfig failingNegotiator(Protocol protocol,
-- String... supportedProtocols) {
-- return new ApplicationProtocolConfig(protocol,
-- SelectorFailureBehavior.FATAL_ALERT,
-- SelectedListenerFailureBehavior.FATAL_ALERT,
-- supportedProtocols);
-- }
--
-- private ApplicationProtocolConfig acceptingNegotiator(Protocol protocol,
-- String... supportedProtocols) {
-- return new ApplicationProtocolConfig(protocol,
-- SelectorFailureBehavior.NO_ADVERTISE,
-- SelectedListenerFailureBehavior.ACCEPT,
-- supportedProtocols);
-- }
--
-- private SkipTestException tlsExtensionNotFound(Protocol protocol) {
-- throw new SkipTestException(protocol + " not on classpath");
-- }
--
-- private static final class SkipTestException extends RuntimeException {
-- public SkipTestException(String message) {
-- super(message);
-- }
-- }
- }
---
-2.7.4
-
diff --git a/0002-Remove-NPN.patch b/0002-Remove-NPN.patch
deleted file mode 100644
index 77a340a..0000000
--- a/0002-Remove-NPN.patch
+++ /dev/null
@@ -1,353 +0,0 @@
-From f7b8e27b5f55c4a21cf84fb56a616b8bfd4af8da Mon Sep 17 00:00:00 2001
-From: Michael Simacek <msimacek(a)redhat.com>
-Date: Fri, 7 Jul 2017 16:07:23 +0200
-Subject: [PATCH 2/3] Remove NPN
-
----
- handler/pom.xml | 5 -
- .../ssl/JdkNpnApplicationProtocolNegotiator.java | 120 --------------------
- .../java/io/netty/handler/ssl/JdkSslContext.java | 30 -----
- .../io/netty/handler/ssl/JettyNpnSslEngine.java | 122 ---------------------
- .../io/netty/handler/ssl/JdkSslEngineTest.java | 2 +-
- 5 files changed, 1 insertion(+), 278 deletions(-)
- delete mode 100644 handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java
- delete mode 100644 handler/src/main/java/io/netty/handler/ssl/JettyNpnSslEngine.java
-
-diff --git a/handler/pom.xml b/handler/pom.xml
-index d0ed1bc..52e63ca 100644
---- a/handler/pom.xml
-+++ b/handler/pom.xml
-@@ -55,11 +55,6 @@
- <optional>true</optional>
- </dependency>
- <dependency>
-- <groupId>org.eclipse.jetty.npn</groupId>
-- <artifactId>npn-api</artifactId>
-- <optional>true</optional>
-- </dependency>
-- <dependency>
- <groupId>org.eclipse.jetty.alpn</groupId>
- <artifactId>alpn-api</artifactId>
- <optional>true</optional>
-diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java b/handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java
-deleted file mode 100644
-index 06b29b7..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java
-+++ /dev/null
-@@ -1,120 +0,0 @@
--/*
-- * Copyright 2014 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
--
--import javax.net.ssl.SSLEngine;
--
--/**
-- * The {@link JdkApplicationProtocolNegotiator} to use if you need NPN and are using {@link SslProvider#JDK}.
-- */
--public final class JdkNpnApplicationProtocolNegotiator extends JdkBaseApplicationProtocolNegotiator {
-- private static final SslEngineWrapperFactory NPN_WRAPPER = new SslEngineWrapperFactory() {
-- {
-- if (!JettyNpnSslEngine.isAvailable()) {
-- throw new RuntimeException("NPN unsupported. Is your classpath configured correctly?"
-- + " See https://wiki.eclipse.org/Jetty/Feature/NPN");
-- }
-- }
--
-- @Override
-- public SSLEngine wrapSslEngine(SSLEngine engine, JdkApplicationProtocolNegotiator applicationNegotiator,
-- boolean isServer) {
-- return new JettyNpnSslEngine(engine, applicationNegotiator, isServer);
-- }
-- };
--
-- /**
-- * Create a new instance.
-- * @param protocols The order of iteration determines the preference of support for protocols.
-- */
-- public JdkNpnApplicationProtocolNegotiator(Iterable<String> protocols) {
-- this(false, protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param protocols The order of iteration determines the preference of support for protocols.
-- */
-- public JdkNpnApplicationProtocolNegotiator(String... protocols) {
-- this(false, protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param failIfNoCommonProtocols Fail with a fatal alert if not common protocols are detected.
-- * @param protocols The order of iteration determines the preference of support for protocols.
-- */
-- public JdkNpnApplicationProtocolNegotiator(boolean failIfNoCommonProtocols, Iterable<String> protocols) {
-- this(failIfNoCommonProtocols, failIfNoCommonProtocols, protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param failIfNoCommonProtocols Fail with a fatal alert if not common protocols are detected.
-- * @param protocols The order of iteration determines the preference of support for protocols.
-- */
-- public JdkNpnApplicationProtocolNegotiator(boolean failIfNoCommonProtocols, String... protocols) {
-- this(failIfNoCommonProtocols, failIfNoCommonProtocols, protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param clientFailIfNoCommonProtocols Client side fail with a fatal alert if not common protocols are detected.
-- * @param serverFailIfNoCommonProtocols Server side fail with a fatal alert if not common protocols are detected.
-- * @param protocols The order of iteration determines the preference of support for protocols.
-- */
-- public JdkNpnApplicationProtocolNegotiator(boolean clientFailIfNoCommonProtocols,
-- boolean serverFailIfNoCommonProtocols, Iterable<String> protocols) {
-- this(clientFailIfNoCommonProtocols ? FAIL_SELECTOR_FACTORY : NO_FAIL_SELECTOR_FACTORY,
-- serverFailIfNoCommonProtocols ? FAIL_SELECTION_LISTENER_FACTORY : NO_FAIL_SELECTION_LISTENER_FACTORY,
-- protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param clientFailIfNoCommonProtocols Client side fail with a fatal alert if not common protocols are detected.
-- * @param serverFailIfNoCommonProtocols Server side fail with a fatal alert if not common protocols are detected.
-- * @param protocols The order of iteration determines the preference of support for protocols.
-- */
-- public JdkNpnApplicationProtocolNegotiator(boolean clientFailIfNoCommonProtocols,
-- boolean serverFailIfNoCommonProtocols, String... protocols) {
-- this(clientFailIfNoCommonProtocols ? FAIL_SELECTOR_FACTORY : NO_FAIL_SELECTOR_FACTORY,
-- serverFailIfNoCommonProtocols ? FAIL_SELECTION_LISTENER_FACTORY : NO_FAIL_SELECTION_LISTENER_FACTORY,
-- protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param selectorFactory The factory which provides classes responsible for selecting the protocol.
-- * @param listenerFactory The factory which provides to be notified of which protocol was selected.
-- * @param protocols The order of iteration determines the preference of support for protocols.
-- */
-- public JdkNpnApplicationProtocolNegotiator(ProtocolSelectorFactory selectorFactory,
-- ProtocolSelectionListenerFactory listenerFactory, Iterable<String> protocols) {
-- super(NPN_WRAPPER, selectorFactory, listenerFactory, protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param selectorFactory The factory which provides classes responsible for selecting the protocol.
-- * @param listenerFactory The factory which provides to be notified of which protocol was selected.
-- * @param protocols The order of iteration determines the preference of support for protocols.
-- */
-- public JdkNpnApplicationProtocolNegotiator(ProtocolSelectorFactory selectorFactory,
-- ProtocolSelectionListenerFactory listenerFactory, String... protocols) {
-- super(NPN_WRAPPER, selectorFactory, listenerFactory, protocols);
-- }
--}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkSslContext.java b/handler/src/main/java/io/netty/handler/ssl/JdkSslContext.java
-index 0ad6639..d5b86ff 100644
---- a/handler/src/main/java/io/netty/handler/ssl/JdkSslContext.java
-+++ b/handler/src/main/java/io/netty/handler/ssl/JdkSslContext.java
-@@ -288,47 +288,17 @@ public class JdkSslContext extends SslContext {
- case ALPN:
- if (isServer) {
- switch(config.selectorFailureBehavior()) {
-- case FATAL_ALERT:
-- return new JdkAlpnApplicationProtocolNegotiator(true, config.supportedProtocols());
-- case NO_ADVERTISE:
-- return new JdkAlpnApplicationProtocolNegotiator(false, config.supportedProtocols());
- default:
- throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ")
- .append(config.selectorFailureBehavior()).append(" failure behavior").toString());
- }
- } else {
- switch(config.selectedListenerFailureBehavior()) {
-- case ACCEPT:
-- return new JdkAlpnApplicationProtocolNegotiator(false, config.supportedProtocols());
-- case FATAL_ALERT:
-- return new JdkAlpnApplicationProtocolNegotiator(true, config.supportedProtocols());
- default:
- throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ")
- .append(config.selectedListenerFailureBehavior()).append(" failure behavior").toString());
- }
- }
-- case NPN:
-- if (isServer) {
-- switch(config.selectedListenerFailureBehavior()) {
-- case ACCEPT:
-- return new JdkNpnApplicationProtocolNegotiator(false, config.supportedProtocols());
-- case FATAL_ALERT:
-- return new JdkNpnApplicationProtocolNegotiator(true, config.supportedProtocols());
-- default:
-- throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ")
-- .append(config.selectedListenerFailureBehavior()).append(" failure behavior").toString());
-- }
-- } else {
-- switch(config.selectorFailureBehavior()) {
-- case FATAL_ALERT:
-- return new JdkNpnApplicationProtocolNegotiator(true, config.supportedProtocols());
-- case NO_ADVERTISE:
-- return new JdkNpnApplicationProtocolNegotiator(false, config.supportedProtocols());
-- default:
-- throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ")
-- .append(config.selectorFailureBehavior()).append(" failure behavior").toString());
-- }
-- }
- default:
- throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ")
- .append(config.protocol()).append(" protocol").toString());
-diff --git a/handler/src/main/java/io/netty/handler/ssl/JettyNpnSslEngine.java b/handler/src/main/java/io/netty/handler/ssl/JettyNpnSslEngine.java
-deleted file mode 100644
-index 77e7366..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/JettyNpnSslEngine.java
-+++ /dev/null
-@@ -1,122 +0,0 @@
--/*
-- * Copyright 2014 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--
--package io.netty.handler.ssl;
--
--import static io.netty.util.internal.ObjectUtil.checkNotNull;
--import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectionListener;
--import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector;
--import io.netty.util.internal.PlatformDependent;
--
--import java.util.LinkedHashSet;
--import java.util.List;
--
--import javax.net.ssl.SSLEngine;
--import javax.net.ssl.SSLException;
--
--import org.eclipse.jetty.npn.NextProtoNego;
--import org.eclipse.jetty.npn.NextProtoNego.ClientProvider;
--import org.eclipse.jetty.npn.NextProtoNego.ServerProvider;
--
--final class JettyNpnSslEngine extends JdkSslEngine {
-- private static boolean available;
--
-- static boolean isAvailable() {
-- updateAvailability();
-- return available;
-- }
--
-- private static void updateAvailability() {
-- if (available) {
-- return;
-- }
-- try {
-- // Always use bootstrap class loader.
-- Class.forName("sun.security.ssl.NextProtoNegoExtension", true, null);
-- available = true;
-- } catch (Exception ignore) {
-- // npn-boot was not loaded.
-- }
-- }
--
-- JettyNpnSslEngine(SSLEngine engine, final JdkApplicationProtocolNegotiator applicationNegotiator, boolean server) {
-- super(engine);
-- checkNotNull(applicationNegotiator, "applicationNegotiator");
--
-- if (server) {
-- final ProtocolSelectionListener protocolListener = checkNotNull(applicationNegotiator
-- .protocolListenerFactory().newListener(this, applicationNegotiator.protocols()),
-- "protocolListener");
-- NextProtoNego.put(engine, new ServerProvider() {
-- @Override
-- public void unsupported() {
-- protocolListener.unsupported();
-- }
--
-- @Override
-- public List<String> protocols() {
-- return applicationNegotiator.protocols();
-- }
--
-- @Override
-- public void protocolSelected(String protocol) {
-- try {
-- protocolListener.selected(protocol);
-- } catch (Throwable t) {
-- PlatformDependent.throwException(t);
-- }
-- }
-- });
-- } else {
-- final ProtocolSelector protocolSelector = checkNotNull(applicationNegotiator.protocolSelectorFactory()
-- .newSelector(this, new LinkedHashSet<String>(applicationNegotiator.protocols())),
-- "protocolSelector");
-- NextProtoNego.put(engine, new ClientProvider() {
-- @Override
-- public boolean supports() {
-- return true;
-- }
--
-- @Override
-- public void unsupported() {
-- protocolSelector.unsupported();
-- }
--
-- @Override
-- public String selectProtocol(List<String> protocols) {
-- try {
-- return protocolSelector.select(protocols);
-- } catch (Throwable t) {
-- PlatformDependent.throwException(t);
-- return null;
-- }
-- }
-- });
-- }
-- }
--
-- @Override
-- public void closeInbound() throws SSLException {
-- NextProtoNego.remove(getWrappedEngine());
-- super.closeInbound();
-- }
--
-- @Override
-- public void closeOutbound() {
-- NextProtoNego.remove(getWrappedEngine());
-- super.closeOutbound();
-- }
--}
-diff --git a/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java b/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java
-index d6cd94d..4489b16 100644
---- a/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java
-+++ b/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java
-@@ -46,7 +46,7 @@ public class JdkSslEngineTest extends SSLEngineTest {
- NPN_DEFAULT {
- @Override
- boolean isAvailable() {
-- return JettyNpnSslEngine.isAvailable();
-+ return false;
- }
-
- @Override
---
-2.9.4
-
diff --git a/0002-Remove-optional-dep-conscrypt.patch b/0002-Remove-optional-dep-conscrypt.patch
new file mode 100644
index 0000000..0a9cfef
--- /dev/null
+++ b/0002-Remove-optional-dep-conscrypt.patch
@@ -0,0 +1,444 @@
+From 1a72454998ec91895648443c176ec41e542903e8 Mon Sep 17 00:00:00 2001
+From: Mat Booth <mat.booth(a)redhat.com>
+Date: Mon, 7 Sep 2020 13:24:30 +0100
+Subject: [PATCH 2/5] Remove optional dep conscrypt
+
+---
+ handler/pom.xml | 6 -
+ .../java/io/netty/handler/ssl/Conscrypt.java | 81 --------
+ .../handler/ssl/ConscryptAlpnSslEngine.java | 196 ------------------
+ .../JdkAlpnApplicationProtocolNegotiator.java | 8 +-
+ .../java/io/netty/handler/ssl/SslHandler.java | 47 +----
+ pom.xml | 10 -
+ 6 files changed, 2 insertions(+), 346 deletions(-)
+ delete mode 100644 handler/src/main/java/io/netty/handler/ssl/Conscrypt.java
+ delete mode 100644 handler/src/main/java/io/netty/handler/ssl/ConscryptAlpnSslEngine.java
+
+diff --git a/handler/pom.xml b/handler/pom.xml
+index c8e26119bd..378aeda2fe 100644
+--- a/handler/pom.xml
++++ b/handler/pom.xml
+@@ -81,12 +81,6 @@
+ <artifactId>alpn-api</artifactId>
+ <optional>true</optional>
+ </dependency>
+- <dependency>
+- <groupId>${conscrypt.groupId}</groupId>
+- <artifactId>${conscrypt.artifactId}</artifactId>
+- <classifier>${conscrypt.classifier}</classifier>
+- <optional>true</optional>
+- </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-core</artifactId>
+diff --git a/handler/src/main/java/io/netty/handler/ssl/Conscrypt.java b/handler/src/main/java/io/netty/handler/ssl/Conscrypt.java
+deleted file mode 100644
+index d2f015f90f..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/Conscrypt.java
++++ /dev/null
+@@ -1,81 +0,0 @@
+-/*
+- * Copyright 2017 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- * http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-package io.netty.handler.ssl;
+-
+-import io.netty.util.internal.PlatformDependent;
+-
+-import javax.net.ssl.SSLEngine;
+-import java.lang.reflect.InvocationTargetException;
+-import java.lang.reflect.Method;
+-
+-/**
+- * Contains methods that can be used to detect if conscrypt is usable.
+- */
+-final class Conscrypt {
+- // This class exists to avoid loading other conscrypt related classes using features only available in JDK8+,
+- // because we need to maintain JDK6+ runtime compatibility.
+- private static final Method IS_CONSCRYPT_SSLENGINE = loadIsConscryptEngine();
+- private static final boolean CAN_INSTANCE_PROVIDER = canInstanceProvider();
+-
+- private static Method loadIsConscryptEngine() {
+- try {
+- Class<?> conscryptClass = Class.forName("org.conscrypt.Conscrypt", true,
+- ConscryptAlpnSslEngine.class.getClassLoader());
+- return conscryptClass.getMethod("isConscrypt", SSLEngine.class);
+- } catch (Throwable ignore) {
+- // Conscrypt was not loaded.
+- return null;
+- }
+- }
+-
+- private static boolean canInstanceProvider() {
+- try {
+- Class<?> providerClass = Class.forName("org.conscrypt.OpenSSLProvider", true,
+- ConscryptAlpnSslEngine.class.getClassLoader());
+- providerClass.newInstance();
+- return true;
+- } catch (Throwable ignore) {
+- return false;
+- }
+- }
+-
+- /**
+- * Indicates whether or not conscrypt is available on the current system.
+- */
+- static boolean isAvailable() {
+- return CAN_INSTANCE_PROVIDER && IS_CONSCRYPT_SSLENGINE != null &&
+- ((PlatformDependent.javaVersion() >= 8 &&
+- // Only works on Java14 and earlier for now
+- // See https://github.com/google/conscrypt/issues/838
+- PlatformDependent.javaVersion() < 15) || PlatformDependent.isAndroid());
+- }
+-
+- static boolean isEngineSupported(SSLEngine engine) {
+- return isAvailable() && isConscryptEngine(engine);
+- }
+-
+- private static boolean isConscryptEngine(SSLEngine engine) {
+- try {
+- return (Boolean) IS_CONSCRYPT_SSLENGINE.invoke(null, engine);
+- } catch (IllegalAccessException ignore) {
+- return false;
+- } catch (InvocationTargetException ex) {
+- throw new RuntimeException(ex);
+- }
+- }
+-
+- private Conscrypt() { }
+-}
+diff --git a/handler/src/main/java/io/netty/handler/ssl/ConscryptAlpnSslEngine.java b/handler/src/main/java/io/netty/handler/ssl/ConscryptAlpnSslEngine.java
+deleted file mode 100644
+index d9767a7106..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/ConscryptAlpnSslEngine.java
++++ /dev/null
+@@ -1,196 +0,0 @@
+-/*
+- * Copyright 2017 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- * http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-package io.netty.handler.ssl;
+-
+-import static io.netty.handler.ssl.SslUtils.toSSLHandshakeException;
+-import static io.netty.util.internal.ObjectUtil.checkNotNull;
+-import static java.lang.Math.min;
+-
+-import io.netty.buffer.ByteBuf;
+-import io.netty.buffer.ByteBufAllocator;
+-import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectionListener;
+-import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector;
+-import java.nio.ByteBuffer;
+-import java.util.Collections;
+-import java.util.LinkedHashSet;
+-import java.util.List;
+-import javax.net.ssl.SSLEngine;
+-import javax.net.ssl.SSLEngineResult;
+-import javax.net.ssl.SSLException;
+-
+-import io.netty.util.internal.SystemPropertyUtil;
+-import org.conscrypt.AllocatedBuffer;
+-import org.conscrypt.BufferAllocator;
+-import org.conscrypt.Conscrypt;
+-import org.conscrypt.HandshakeListener;
+-
+-/**
+- * A {@link JdkSslEngine} that uses the Conscrypt provider or SSL with ALPN.
+- */
+-abstract class ConscryptAlpnSslEngine extends JdkSslEngine {
+- private static final boolean USE_BUFFER_ALLOCATOR = SystemPropertyUtil.getBoolean(
+- "io.netty.handler.ssl.conscrypt.useBufferAllocator", true);
+-
+- static ConscryptAlpnSslEngine newClientEngine(SSLEngine engine, ByteBufAllocator alloc,
+- JdkApplicationProtocolNegotiator applicationNegotiator) {
+- return new ClientEngine(engine, alloc, applicationNegotiator);
+- }
+-
+- static ConscryptAlpnSslEngine newServerEngine(SSLEngine engine, ByteBufAllocator alloc,
+- JdkApplicationProtocolNegotiator applicationNegotiator) {
+- return new ServerEngine(engine, alloc, applicationNegotiator);
+- }
+-
+- private ConscryptAlpnSslEngine(SSLEngine engine, ByteBufAllocator alloc, List<String> protocols) {
+- super(engine);
+-
+- // Configure the Conscrypt engine to use Netty's buffer allocator. This is a trade-off of memory vs
+- // performance.
+- //
+- // If no allocator is provided, the engine will internally allocate a direct buffer of max packet size in
+- // order to optimize JNI calls (this happens the first time it is provided a non-direct buffer from the
+- // application).
+- //
+- // Alternatively, if an allocator is provided, no internal buffer will be created and direct buffers will be
+- // retrieved from the allocator on-demand.
+- if (USE_BUFFER_ALLOCATOR) {
+- Conscrypt.setBufferAllocator(engine, new BufferAllocatorAdapter(alloc));
+- }
+-
+- // Set the list of supported ALPN protocols on the engine.
+- Conscrypt.setApplicationProtocols(engine, protocols.toArray(new String[0]));
+- }
+-
+- /**
+- * Calculates the maximum size of the encrypted output buffer required to wrap the given plaintext bytes. Assumes
+- * as a worst case that there is one TLS record per buffer.
+- *
+- * @param plaintextBytes the number of plaintext bytes to be wrapped.
+- * @param numBuffers the number of buffers that the plaintext bytes are spread across.
+- * @return the maximum size of the encrypted output buffer required for the wrap operation.
+- */
+- final int calculateOutNetBufSize(int plaintextBytes, int numBuffers) {
+- // Assuming a max of one frame per component in a composite buffer.
+- long maxOverhead = (long) Conscrypt.maxSealOverhead(getWrappedEngine()) * numBuffers;
+- // TODO(nmittler): update this to use MAX_ENCRYPTED_PACKET_LENGTH instead of Integer.MAX_VALUE
+- return (int) min(Integer.MAX_VALUE, plaintextBytes + maxOverhead);
+- }
+-
+- final SSLEngineResult unwrap(ByteBuffer[] srcs, ByteBuffer[] dests) throws SSLException {
+- return Conscrypt.unwrap(getWrappedEngine(), srcs, dests);
+- }
+-
+- private static final class ClientEngine extends ConscryptAlpnSslEngine {
+- private final ProtocolSelectionListener protocolListener;
+-
+- ClientEngine(SSLEngine engine, ByteBufAllocator alloc,
+- JdkApplicationProtocolNegotiator applicationNegotiator) {
+- super(engine, alloc, applicationNegotiator.protocols());
+- // Register for completion of the handshake.
+- Conscrypt.setHandshakeListener(engine, new HandshakeListener() {
+- @Override
+- public void onHandshakeFinished() throws SSLException {
+- selectProtocol();
+- }
+- });
+-
+- protocolListener = checkNotNull(applicationNegotiator
+- .protocolListenerFactory().newListener(this, applicationNegotiator.protocols()),
+- "protocolListener");
+- }
+-
+- private void selectProtocol() throws SSLException {
+- String protocol = Conscrypt.getApplicationProtocol(getWrappedEngine());
+- try {
+- protocolListener.selected(protocol);
+- } catch (Throwable e) {
+- throw toSSLHandshakeException(e);
+- }
+- }
+- }
+-
+- private static final class ServerEngine extends ConscryptAlpnSslEngine {
+- private final ProtocolSelector protocolSelector;
+-
+- ServerEngine(SSLEngine engine, ByteBufAllocator alloc,
+- JdkApplicationProtocolNegotiator applicationNegotiator) {
+- super(engine, alloc, applicationNegotiator.protocols());
+-
+- // Register for completion of the handshake.
+- Conscrypt.setHandshakeListener(engine, new HandshakeListener() {
+- @Override
+- public void onHandshakeFinished() throws SSLException {
+- selectProtocol();
+- }
+- });
+-
+- protocolSelector = checkNotNull(applicationNegotiator.protocolSelectorFactory()
+- .newSelector(this,
+- new LinkedHashSet<String>(applicationNegotiator.protocols())),
+- "protocolSelector");
+- }
+-
+- private void selectProtocol() throws SSLException {
+- try {
+- String protocol = Conscrypt.getApplicationProtocol(getWrappedEngine());
+- protocolSelector.select(protocol != null ? Collections.singletonList(protocol)
+- : Collections.<String>emptyList());
+- } catch (Throwable e) {
+- throw toSSLHandshakeException(e);
+- }
+- }
+- }
+-
+- private static final class BufferAllocatorAdapter extends BufferAllocator {
+- private final ByteBufAllocator alloc;
+-
+- BufferAllocatorAdapter(ByteBufAllocator alloc) {
+- this.alloc = alloc;
+- }
+-
+- @Override
+- public AllocatedBuffer allocateDirectBuffer(int capacity) {
+- return new BufferAdapter(alloc.directBuffer(capacity));
+- }
+- }
+-
+- private static final class BufferAdapter extends AllocatedBuffer {
+- private final ByteBuf nettyBuffer;
+- private final ByteBuffer buffer;
+-
+- BufferAdapter(ByteBuf nettyBuffer) {
+- this.nettyBuffer = nettyBuffer;
+- buffer = nettyBuffer.nioBuffer(0, nettyBuffer.capacity());
+- }
+-
+- @Override
+- public ByteBuffer nioBuffer() {
+- return buffer;
+- }
+-
+- @Override
+- public AllocatedBuffer retain() {
+- nettyBuffer.retain();
+- return this;
+- }
+-
+- @Override
+- public AllocatedBuffer release() {
+- nettyBuffer.release();
+- return this;
+- }
+- }
+-}
+diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java b/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java
+index c4ca7b9b8c..2ed83a313b 100644
+--- a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java
++++ b/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java
+@@ -26,8 +26,7 @@ import javax.net.ssl.SSLEngine;
+ */
+ @Deprecated
+ public final class JdkAlpnApplicationProtocolNegotiator extends JdkBaseApplicationProtocolNegotiator {
+- private static final boolean AVAILABLE = Conscrypt.isAvailable() ||
+- JdkAlpnSslUtils.supportsAlpn() ||
++ private static final boolean AVAILABLE = JdkAlpnSslUtils.supportsAlpn() ||
+ JettyAlpnSslEngine.isAvailable();
+
+ private static final SslEngineWrapperFactory ALPN_WRAPPER = AVAILABLE ? new AlpnWrapper() : new FailureWrapper();
+@@ -119,7 +118,6 @@ public final class JdkAlpnApplicationProtocolNegotiator extends JdkBaseApplicati
+ public SSLEngine wrapSslEngine(SSLEngine engine, ByteBufAllocator alloc,
+ JdkApplicationProtocolNegotiator applicationNegotiator, boolean isServer) {
+ throw new RuntimeException("ALPN unsupported. Is your classpath configured correctly?"
+- + " For Conscrypt, add the appropriate Conscrypt JAR to classpath and set the security provider."
+ + " For Jetty-ALPN, see "
+ + "http://www.eclipse.org/jetty/documentation/current/alpn-chapter.html#alpn...");
+ }
+@@ -129,10 +127,6 @@ public final class JdkAlpnApplicationProtocolNegotiator extends JdkBaseApplicati
+ @Override
+ public SSLEngine wrapSslEngine(SSLEngine engine, ByteBufAllocator alloc,
+ JdkApplicationProtocolNegotiator applicationNegotiator, boolean isServer) {
+- if (Conscrypt.isEngineSupported(engine)) {
+- return isServer ? ConscryptAlpnSslEngine.newServerEngine(engine, alloc, applicationNegotiator)
+- : ConscryptAlpnSslEngine.newClientEngine(engine, alloc, applicationNegotiator);
+- }
+ // ALPN support was recently backported to Java8 as
+ // https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8230977.
+ // Because of this lets not do a Java version runtime check but just depend on if the required methods are
+diff --git a/handler/src/main/java/io/netty/handler/ssl/SslHandler.java b/handler/src/main/java/io/netty/handler/ssl/SslHandler.java
+index de101967ba..8e11bbf4cc 100644
+--- a/handler/src/main/java/io/netty/handler/ssl/SslHandler.java
++++ b/handler/src/main/java/io/netty/handler/ssl/SslHandler.java
+@@ -228,50 +228,6 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
+ return ((ReferenceCountedOpenSslEngine) engine).jdkCompatibilityMode;
+ }
+ },
+- CONSCRYPT(true, COMPOSITE_CUMULATOR) {
+- @Override
+- SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int len, ByteBuf out)
+- throws SSLException {
+- int nioBufferCount = in.nioBufferCount();
+- int writerIndex = out.writerIndex();
+- final SSLEngineResult result;
+- if (nioBufferCount > 1) {
+- /*
+- * Use a special unwrap method without additional memory copies.
+- */
+- try {
+- handler.singleBuffer[0] = toByteBuffer(out, writerIndex, out.writableBytes());
+- result = ((ConscryptAlpnSslEngine) handler.engine).unwrap(
+- in.nioBuffers(readerIndex, len),
+- handler.singleBuffer);
+- } finally {
+- handler.singleBuffer[0] = null;
+- }
+- } else {
+- result = handler.engine.unwrap(toByteBuffer(in, readerIndex, len),
+- toByteBuffer(out, writerIndex, out.writableBytes()));
+- }
+- out.writerIndex(writerIndex + result.bytesProduced());
+- return result;
+- }
+-
+- @Override
+- ByteBuf allocateWrapBuffer(SslHandler handler, ByteBufAllocator allocator,
+- int pendingBytes, int numComponents) {
+- return allocator.directBuffer(
+- ((ConscryptAlpnSslEngine) handler.engine).calculateOutNetBufSize(pendingBytes, numComponents));
+- }
+-
+- @Override
+- int calculatePendingData(SslHandler handler, int guess) {
+- return guess;
+- }
+-
+- @Override
+- boolean jdkCompatibilityMode(SSLEngine engine) {
+- return true;
+- }
+- },
+ JDK(false, MERGE_CUMULATOR) {
+ @Override
+ SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int len, ByteBuf out)
+@@ -324,8 +280,7 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
+ };
+
+ static SslEngineType forEngine(SSLEngine engine) {
+- return engine instanceof ReferenceCountedOpenSslEngine ? TCNATIVE :
+- engine instanceof ConscryptAlpnSslEngine ? CONSCRYPT : JDK;
++ return engine instanceof ReferenceCountedOpenSslEngine ? TCNATIVE : JDK;
+ }
+
+ SslEngineType(boolean wantsDirectBuffer, Cumulator cumulator) {
+diff --git a/pom.xml b/pom.xml
+index d548aa5513..db3d7b0d38 100644
+--- a/pom.xml
++++ b/pom.xml
+@@ -489,16 +489,6 @@
+ <optional>true</optional>
+ </dependency>
+
+- <!-- Conscrypt - needed for running tests, used for acclerating SSL with OpenSSL. -->
+- <dependency>
+- <groupId>${conscrypt.groupId}</groupId>
+- <artifactId>${conscrypt.artifactId}</artifactId>
+- <classifier>${conscrypt.classifier}</classifier>
+- <version>${conscrypt.version}</version>
+- <scope>compile</scope>
+- <optional>true</optional>
+- </dependency>
+-
+ <!--
+ Bouncy Castle - completely optional, only needed when:
+ - you generate a temporary self-signed certificate using SelfSignedCertificate, and
+--
+2.26.2
+
diff --git a/0003-Remove-conscrypt-ALPN.patch b/0003-Remove-conscrypt-ALPN.patch
deleted file mode 100644
index e71ba5a..0000000
--- a/0003-Remove-conscrypt-ALPN.patch
+++ /dev/null
@@ -1,511 +0,0 @@
-From 039534e20546221c3466d1ceb663625c59edb0e7 Mon Sep 17 00:00:00 2001
-From: Michael Simacek <msimacek(a)redhat.com>
-Date: Tue, 11 Jul 2017 13:37:22 +0200
-Subject: [PATCH 3/3] Remove conscrypt ALPN
-
----
- handler/pom.xml | 6 -
- .../netty/handler/ssl/ConscryptAlpnSslEngine.java | 176 ---------------------
- .../ssl/JdkAlpnApplicationProtocolNegotiator.java | 6 +-
- .../main/java/io/netty/handler/ssl/SslHandler.java | 35 ----
- .../ssl/ConscryptJdkSslEngineInteropTest.java | 76 ---------
- .../io/netty/handler/ssl/Java8SslTestUtils.java | 7 -
- .../ssl/JdkConscryptSslEngineInteropTest.java | 86 ----------
- .../io/netty/handler/ssl/JdkSslEngineTest.java | 2 +-
- 8 files changed, 2 insertions(+), 392 deletions(-)
- delete mode 100644 handler/src/main/java/io/netty/handler/ssl/ConscryptAlpnSslEngine.java
- delete mode 100644 handler/src/test/java/io/netty/handler/ssl/ConscryptJdkSslEngineInteropTest.java
- delete mode 100644 handler/src/test/java/io/netty/handler/ssl/JdkConscryptSslEngineInteropTest.java
-
-diff --git a/handler/pom.xml b/handler/pom.xml
-index 52e63ca..69af32a 100644
---- a/handler/pom.xml
-+++ b/handler/pom.xml
-@@ -60,12 +60,6 @@
- <optional>true</optional>
- </dependency>
- <dependency>
-- <groupId>${conscrypt.groupId}</groupId>
-- <artifactId>${conscrypt.artifactId}</artifactId>
-- <classifier>${conscrypt.classifier}</classifier>
-- <optional>true</optional>
-- </dependency>
-- <dependency>
- <groupId>org.mockito</groupId>
- <artifactId>mockito-core</artifactId>
- </dependency>
-diff --git a/handler/src/main/java/io/netty/handler/ssl/ConscryptAlpnSslEngine.java b/handler/src/main/java/io/netty/handler/ssl/ConscryptAlpnSslEngine.java
-deleted file mode 100644
-index 8e7a544..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/ConscryptAlpnSslEngine.java
-+++ /dev/null
-@@ -1,176 +0,0 @@
--/*
-- * Copyright 2017 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
--
--import static io.netty.handler.ssl.SslUtils.toSSLHandshakeException;
--import static io.netty.util.internal.ObjectUtil.checkNotNull;
--import static java.lang.Math.min;
--
--import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectionListener;
--import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector;
--import java.lang.reflect.Method;
--import java.nio.ByteBuffer;
--import java.util.Collections;
--import java.util.LinkedHashSet;
--import java.util.List;
--import javax.net.ssl.SSLEngine;
--import javax.net.ssl.SSLEngineResult;
--import javax.net.ssl.SSLException;
--
--import io.netty.util.internal.PlatformDependent;
--import org.conscrypt.Conscrypt;
--import org.conscrypt.HandshakeListener;
--
--/**
-- * A {@link JdkSslEngine} that uses the Conscrypt provider or SSL with ALPN.
-- */
--abstract class ConscryptAlpnSslEngine extends JdkSslEngine {
-- private static final Class<?> ENGINES_CLASS = getEnginesClass();
--
-- /**
-- * Indicates whether or not conscrypt is available on the current system.
-- */
-- static boolean isAvailable() {
-- return ENGINES_CLASS != null && PlatformDependent.javaVersion() >= 8;
-- }
--
-- static boolean isEngineSupported(SSLEngine engine) {
-- return isAvailable() && isConscryptEngine(engine, ENGINES_CLASS);
-- }
--
-- static ConscryptAlpnSslEngine newClientEngine(SSLEngine engine,
-- JdkApplicationProtocolNegotiator applicationNegotiator) {
-- return new ClientEngine(engine, applicationNegotiator);
-- }
--
-- static ConscryptAlpnSslEngine newServerEngine(SSLEngine engine,
-- JdkApplicationProtocolNegotiator applicationNegotiator) {
-- return new ServerEngine(engine, applicationNegotiator);
-- }
--
-- private ConscryptAlpnSslEngine(SSLEngine engine, List<String> protocols) {
-- super(engine);
--
-- // Set the list of supported ALPN protocols on the engine.
-- Conscrypt.Engines.setAlpnProtocols(engine, protocols.toArray(new String[protocols.size()]));
-- }
--
-- /**
-- * Calculates the maximum size of the encrypted output buffer required to wrap the given plaintext bytes. Assumes
-- * as a worst case that there is one TLS record per buffer.
-- *
-- * @param plaintextBytes the number of plaintext bytes to be wrapped.
-- * @param numBuffers the number of buffers that the plaintext bytes are spread across.
-- * @return the maximum size of the encrypted output buffer required for the wrap operation.
-- */
-- final int calculateOutNetBufSize(int plaintextBytes, int numBuffers) {
-- // Assuming a max of one frame per component in a composite buffer.
-- long maxOverhead = (long) Conscrypt.Engines.maxSealOverhead(getWrappedEngine()) * numBuffers;
-- // TODO(nmittler): update this to use MAX_ENCRYPTED_PACKET_LENGTH instead of Integer.MAX_VALUE
-- return (int) min(Integer.MAX_VALUE, plaintextBytes + maxOverhead);
-- }
--
-- final SSLEngineResult unwrap(ByteBuffer[] srcs, ByteBuffer[] dests) throws SSLException {
-- return Conscrypt.Engines.unwrap(getWrappedEngine(), srcs, dests);
-- }
--
-- private static final class ClientEngine extends ConscryptAlpnSslEngine {
-- private final ProtocolSelectionListener protocolListener;
--
-- ClientEngine(SSLEngine engine,
-- JdkApplicationProtocolNegotiator applicationNegotiator) {
-- super(engine, applicationNegotiator.protocols());
-- // Register for completion of the handshake.
-- Conscrypt.Engines.setHandshakeListener(engine, new HandshakeListener() {
-- @Override
-- public void onHandshakeFinished() throws SSLException {
-- selectProtocol();
-- }
-- });
--
-- protocolListener = checkNotNull(applicationNegotiator
-- .protocolListenerFactory().newListener(this, applicationNegotiator.protocols()),
-- "protocolListener");
-- }
--
-- private void selectProtocol() throws SSLException {
-- String protocol = Conscrypt.Engines.getAlpnSelectedProtocol(getWrappedEngine());
-- try {
-- protocolListener.selected(protocol);
-- } catch (Throwable e) {
-- throw toSSLHandshakeException(e);
-- }
-- }
-- }
--
-- private static final class ServerEngine extends ConscryptAlpnSslEngine {
-- private final ProtocolSelector protocolSelector;
--
-- ServerEngine(SSLEngine engine, JdkApplicationProtocolNegotiator applicationNegotiator) {
-- super(engine, applicationNegotiator.protocols());
--
-- // Register for completion of the handshake.
-- Conscrypt.Engines.setHandshakeListener(engine, new HandshakeListener() {
-- @Override
-- public void onHandshakeFinished() throws SSLException {
-- selectProtocol();
-- }
-- });
--
-- protocolSelector = checkNotNull(applicationNegotiator.protocolSelectorFactory()
-- .newSelector(this,
-- new LinkedHashSet<String>(applicationNegotiator.protocols())),
-- "protocolSelector");
-- }
--
-- private void selectProtocol() throws SSLException {
-- try {
-- String protocol = Conscrypt.Engines.getAlpnSelectedProtocol(getWrappedEngine());
-- protocolSelector.select(protocol != null ? Collections.singletonList(protocol)
-- : Collections.<String>emptyList());
-- } catch (Throwable e) {
-- throw toSSLHandshakeException(e);
-- }
-- }
-- }
--
-- private static Class<?> getEnginesClass() {
-- try {
-- // Always use bootstrap class loader.
-- Class<?> engineClass = Class.forName("org.conscrypt.Conscrypt$Engines", true,
-- ConscryptAlpnSslEngine.class.getClassLoader());
-- // Ensure that it also has the isConscrypt method.
-- getIsConscryptMethod(engineClass);
-- return engineClass;
-- } catch (Throwable ignore) {
-- // Conscrypt was not loaded.
-- return null;
-- }
-- }
--
-- private static boolean isConscryptEngine(SSLEngine engine, Class<?> enginesClass) {
-- try {
-- Method method = getIsConscryptMethod(enginesClass);
-- return (Boolean) method.invoke(null, engine);
-- } catch (Throwable ignore) {
-- return false;
-- }
-- }
--
-- private static Method getIsConscryptMethod(Class<?> enginesClass) throws NoSuchMethodException {
-- return enginesClass.getMethod("isConscrypt", SSLEngine.class);
-- }
--}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java b/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java
-index f82c7da..9c4ab9e 100644
---- a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java
-+++ b/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java
-@@ -21,7 +21,7 @@ import javax.net.ssl.SSLEngine;
- * The {@link JdkApplicationProtocolNegotiator} to use if you need ALPN and are using {@link SslProvider#JDK}.
- */
- public final class JdkAlpnApplicationProtocolNegotiator extends JdkBaseApplicationProtocolNegotiator {
-- private static final boolean AVAILABLE = ConscryptAlpnSslEngine.isAvailable() || JettyAlpnSslEngine.isAvailable();
-+ private static final boolean AVAILABLE = JettyAlpnSslEngine.isAvailable();
- private static final SslEngineWrapperFactory ALPN_WRAPPER = AVAILABLE ? new AlpnWrapper() : new FailureWrapper();
-
- /**
-@@ -121,10 +121,6 @@ public final class JdkAlpnApplicationProtocolNegotiator extends JdkBaseApplicati
- @Override
- public SSLEngine wrapSslEngine(SSLEngine engine, JdkApplicationProtocolNegotiator applicationNegotiator,
- boolean isServer) {
-- if (ConscryptAlpnSslEngine.isEngineSupported(engine)) {
-- return isServer ? ConscryptAlpnSslEngine.newServerEngine(engine, applicationNegotiator)
-- : ConscryptAlpnSslEngine.newClientEngine(engine, applicationNegotiator);
-- }
- if (JettyAlpnSslEngine.isAvailable()) {
- return isServer ? JettyAlpnSslEngine.newServerEngine(engine, applicationNegotiator)
- : JettyAlpnSslEngine.newClientEngine(engine, applicationNegotiator);
-diff --git a/handler/src/main/java/io/netty/handler/ssl/SslHandler.java b/handler/src/main/java/io/netty/handler/ssl/SslHandler.java
-index 05c451a..8693011 100644
---- a/handler/src/main/java/io/netty/handler/ssl/SslHandler.java
-+++ b/handler/src/main/java/io/netty/handler/ssl/SslHandler.java
-@@ -187,38 +187,6 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
- new ClosedChannelException(), SslHandler.class, "channelInactive(...)");
-
- private enum SslEngineType {
-- CONSCRYPT(true, COMPOSITE_CUMULATOR) {
-- @Override
-- SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int len, ByteBuf out)
-- throws SSLException {
-- int nioBufferCount = in.nioBufferCount();
-- int writerIndex = out.writerIndex();
-- final SSLEngineResult result;
-- if (nioBufferCount > 1) {
-- /*
-- * Use a special unwrap method without additional memory copies.
-- */
-- try {
-- handler.singleBuffer[0] = toByteBuffer(out, writerIndex, out.writableBytes());
-- result = ((ConscryptAlpnSslEngine) handler.engine).unwrap(
-- in.nioBuffers(readerIndex, len),
-- handler.singleBuffer);
-- } finally {
-- handler.singleBuffer[0] = null;
-- }
-- } else {
-- result = handler.engine.unwrap(toByteBuffer(in, readerIndex, len),
-- toByteBuffer(out, writerIndex, out.writableBytes()));
-- }
-- out.writerIndex(writerIndex + result.bytesProduced());
-- return result;
-- }
--
-- @Override
-- int calculateWrapBufferCapacity(SslHandler handler, int pendingBytes, int numComponents) {
-- return ((ConscryptAlpnSslEngine) handler.engine).calculateOutNetBufSize(pendingBytes, numComponents);
-- }
-- },
- JDK(false, MERGE_CUMULATOR) {
- @Override
- SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int len, ByteBuf out)
-@@ -237,9 +205,6 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
- };
-
- static SslEngineType forEngine(SSLEngine engine) {
-- if (engine instanceof ConscryptAlpnSslEngine) {
-- return CONSCRYPT;
-- }
- return JDK;
- }
-
-diff --git a/handler/src/test/java/io/netty/handler/ssl/ConscryptJdkSslEngineInteropTest.java b/handler/src/test/java/io/netty/handler/ssl/ConscryptJdkSslEngineInteropTest.java
-deleted file mode 100644
-index e217136..0000000
---- a/handler/src/test/java/io/netty/handler/ssl/ConscryptJdkSslEngineInteropTest.java
-+++ /dev/null
-@@ -1,76 +0,0 @@
--/*
-- * Copyright 2016 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
--
--import java.security.Provider;
--import org.junit.BeforeClass;
--import org.junit.Ignore;
--
--import org.junit.runner.RunWith;
--import org.junit.runners.Parameterized;
--
--import java.util.ArrayList;
--import java.util.Collection;
--import java.util.List;
--
--import static org.junit.Assume.assumeTrue;
--
--(a)RunWith(Parameterized.class)
--public class ConscryptJdkSslEngineInteropTest extends SSLEngineTest {
--
-- @Parameterized.Parameters(name = "{index}: bufferType = {0}")
-- public static Collection<Object> data() {
-- List<Object> params = new ArrayList<Object>();
-- for (BufferType type: BufferType.values()) {
-- params.add(type);
-- }
-- return params;
-- }
--
-- public ConscryptJdkSslEngineInteropTest(BufferType type) {
-- super(type);
-- }
--
-- @BeforeClass
-- public static void checkConscrypt() {
-- assumeTrue(ConscryptAlpnSslEngine.isAvailable());
-- }
--
-- @Override
-- protected SslProvider sslClientProvider() {
-- return SslProvider.JDK;
-- }
--
-- @Override
-- protected SslProvider sslServerProvider() {
-- return SslProvider.JDK;
-- }
--
-- @Override
-- protected Provider clientSslContextProvider() {
-- return Java8SslTestUtils.conscryptProvider();
-- }
--
-- @Ignore /* Does the JDK support a "max certificate chain length"? */
-- @Override
-- public void testMutualAuthValidClientCertChainTooLongFailOptionalClientAuth() throws Exception {
-- }
--
-- @Ignore /* Does the JDK support a "max certificate chain length"? */
-- @Override
-- public void testMutualAuthValidClientCertChainTooLongFailRequireClientAuth() throws Exception {
-- }
--}
-diff --git a/handler/src/test/java/io/netty/handler/ssl/Java8SslTestUtils.java b/handler/src/test/java/io/netty/handler/ssl/Java8SslTestUtils.java
-index cc2e6c6..f9cf771 100644
---- a/handler/src/test/java/io/netty/handler/ssl/Java8SslTestUtils.java
-+++ b/handler/src/test/java/io/netty/handler/ssl/Java8SslTestUtils.java
-@@ -16,12 +16,9 @@
-
- package io.netty.handler.ssl;
-
--import org.conscrypt.OpenSSLProvider;
--
- import javax.net.ssl.SNIMatcher;
- import javax.net.ssl.SNIServerName;
- import javax.net.ssl.SSLParameters;
--import java.security.Provider;
- import java.util.Collections;
-
- final class Java8SslTestUtils {
-@@ -37,8 +34,4 @@ final class Java8SslTestUtils {
- };
- parameters.setSNIMatchers(Collections.singleton(matcher));
- }
--
-- static Provider conscryptProvider() {
-- return new OpenSSLProvider();
-- }
- }
-diff --git a/handler/src/test/java/io/netty/handler/ssl/JdkConscryptSslEngineInteropTest.java b/handler/src/test/java/io/netty/handler/ssl/JdkConscryptSslEngineInteropTest.java
-deleted file mode 100644
-index 0625f7a..0000000
---- a/handler/src/test/java/io/netty/handler/ssl/JdkConscryptSslEngineInteropTest.java
-+++ /dev/null
-@@ -1,86 +0,0 @@
--/*
-- * Copyright 2017 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
--
--import java.security.Provider;
--import org.junit.BeforeClass;
--import org.junit.Ignore;
--import org.junit.Test;
--import org.junit.runner.RunWith;
--import org.junit.runners.Parameterized;
--
--import java.util.ArrayList;
--import java.util.Collection;
--import java.util.List;
--
--import static org.junit.Assume.assumeTrue;
--
--(a)RunWith(Parameterized.class)
--public class JdkConscryptSslEngineInteropTest extends SSLEngineTest {
--
-- @Parameterized.Parameters(name = "{index}: bufferType = {0}")
-- public static Collection<Object> data() {
-- List<Object> params = new ArrayList<Object>();
-- for (BufferType type: BufferType.values()) {
-- params.add(type);
-- }
-- return params;
-- }
--
-- public JdkConscryptSslEngineInteropTest(BufferType type) {
-- super(type);
-- }
--
-- @BeforeClass
-- public static void checkConscrypt() {
-- assumeTrue(ConscryptAlpnSslEngine.isAvailable());
-- }
--
-- @Override
-- protected SslProvider sslClientProvider() {
-- return SslProvider.JDK;
-- }
--
-- @Override
-- protected SslProvider sslServerProvider() {
-- return SslProvider.JDK;
-- }
--
-- @Override
-- protected Provider serverSslContextProvider() {
-- return Java8SslTestUtils.conscryptProvider();
-- }
--
-- @Override
-- @Test
-- @Ignore("TODO: Make this work with Conscrypt")
-- public void testMutualAuthValidClientCertChainTooLongFailOptionalClientAuth() throws Exception {
-- super.testMutualAuthValidClientCertChainTooLongFailOptionalClientAuth();
-- }
--
-- @Override
-- @Test
-- @Ignore("TODO: Make this work with Conscrypt")
-- public void testMutualAuthValidClientCertChainTooLongFailRequireClientAuth() throws Exception {
-- super.testMutualAuthValidClientCertChainTooLongFailRequireClientAuth();
-- }
--
-- @Override
-- protected boolean mySetupMutualAuthServerIsValidClientException(Throwable cause) {
-- // TODO(scott): work around for a JDK issue. The exception should be SSLHandshakeException.
-- return super.mySetupMutualAuthServerIsValidClientException(cause) || causedBySSLException(cause);
-- }
--}
-diff --git a/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java b/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java
-index 4489b16..e32fa0d 100644
---- a/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java
-+++ b/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java
-@@ -81,7 +81,7 @@ public class JdkSslEngineTest extends SSLEngineTest {
-
- @Override
- boolean isAvailable() {
-- return ConscryptAlpnSslEngine.isAvailable();
-+ return false;
- }
-
- @Override
---
-2.9.4
-
diff --git a/0003-Remove-optional-deps-jetty-alpn-and-npn.patch b/0003-Remove-optional-deps-jetty-alpn-and-npn.patch
new file mode 100644
index 0000000..6e74960
--- /dev/null
+++ b/0003-Remove-optional-deps-jetty-alpn-and-npn.patch
@@ -0,0 +1,405 @@
+From cb6b51eed1faef580120e19aa1b5404c19a9398b Mon Sep 17 00:00:00 2001
+From: Mat Booth <mat.booth(a)redhat.com>
+Date: Mon, 7 Sep 2020 13:26:20 +0100
+Subject: [PATCH 3/5] Remove optional deps jetty alpn and npn
+
+---
+ handler/pom.xml | 10 --
+ .../JdkAlpnApplicationProtocolNegotiator.java | 7 +-
+ .../JdkNpnApplicationProtocolNegotiator.java | 10 +-
+ .../netty/handler/ssl/JettyAlpnSslEngine.java | 157 ------------------
+ .../netty/handler/ssl/JettyNpnSslEngine.java | 122 --------------
+ pom.xml | 14 --
+ 6 files changed, 3 insertions(+), 317 deletions(-)
+ delete mode 100644 handler/src/main/java/io/netty/handler/ssl/JettyAlpnSslEngine.java
+ delete mode 100644 handler/src/main/java/io/netty/handler/ssl/JettyNpnSslEngine.java
+
+diff --git a/handler/pom.xml b/handler/pom.xml
+index 378aeda2fe..be8206dc89 100644
+--- a/handler/pom.xml
++++ b/handler/pom.xml
+@@ -71,16 +71,6 @@
+ <artifactId>bcpkix-jdk15on</artifactId>
+ <optional>true</optional>
+ </dependency>
+- <dependency>
+- <groupId>org.eclipse.jetty.npn</groupId>
+- <artifactId>npn-api</artifactId>
+- <optional>true</optional>
+- </dependency>
+- <dependency>
+- <groupId>org.eclipse.jetty.alpn</groupId>
+- <artifactId>alpn-api</artifactId>
+- <optional>true</optional>
+- </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-core</artifactId>
+diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java b/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java
+index 2ed83a313b..dbd5ed9f07 100644
+--- a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java
++++ b/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java
+@@ -26,8 +26,7 @@ import javax.net.ssl.SSLEngine;
+ */
+ @Deprecated
+ public final class JdkAlpnApplicationProtocolNegotiator extends JdkBaseApplicationProtocolNegotiator {
+- private static final boolean AVAILABLE = JdkAlpnSslUtils.supportsAlpn() ||
+- JettyAlpnSslEngine.isAvailable();
++ private static final boolean AVAILABLE = JdkAlpnSslUtils.supportsAlpn();
+
+ private static final SslEngineWrapperFactory ALPN_WRAPPER = AVAILABLE ? new AlpnWrapper() : new FailureWrapper();
+
+@@ -134,10 +133,6 @@ public final class JdkAlpnApplicationProtocolNegotiator extends JdkBaseApplicati
+ if (JdkAlpnSslUtils.supportsAlpn()) {
+ return new JdkAlpnSslEngine(engine, applicationNegotiator, isServer);
+ }
+- if (JettyAlpnSslEngine.isAvailable()) {
+- return isServer ? JettyAlpnSslEngine.newServerEngine(engine, applicationNegotiator)
+- : JettyAlpnSslEngine.newClientEngine(engine, applicationNegotiator);
+- }
+ throw new UnsupportedOperationException("ALPN not supported. Unable to wrap SSLEngine of type '"
+ + engine.getClass().getName() + "')");
+ }
+diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java b/handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java
+index 3c2863b66c..2703336e8b 100644
+--- a/handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java
++++ b/handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java
+@@ -25,17 +25,11 @@ import javax.net.ssl.SSLEngine;
+ @Deprecated
+ public final class JdkNpnApplicationProtocolNegotiator extends JdkBaseApplicationProtocolNegotiator {
+ private static final SslEngineWrapperFactory NPN_WRAPPER = new SslEngineWrapperFactory() {
+- {
+- if (!JettyNpnSslEngine.isAvailable()) {
+- throw new RuntimeException("NPN unsupported. Is your classpath configured correctly?"
+- + " See https://wiki.eclipse.org/Jetty/Feature/NPN");
+- }
+- }
+-
+ @Override
+ public SSLEngine wrapSslEngine(SSLEngine engine,
+ JdkApplicationProtocolNegotiator applicationNegotiator, boolean isServer) {
+- return new JettyNpnSslEngine(engine, applicationNegotiator, isServer);
++ throw new UnsupportedOperationException("NPN not supported. Unable to wrap SSLEngine of type '"
++ + engine.getClass().getName() + "')");
+ }
+ };
+
+diff --git a/handler/src/main/java/io/netty/handler/ssl/JettyAlpnSslEngine.java b/handler/src/main/java/io/netty/handler/ssl/JettyAlpnSslEngine.java
+deleted file mode 100644
+index ce9f14a57e..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/JettyAlpnSslEngine.java
++++ /dev/null
+@@ -1,157 +0,0 @@
+-/*
+- * Copyright 2014 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- * http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-package io.netty.handler.ssl;
+-
+-import static io.netty.handler.ssl.SslUtils.toSSLHandshakeException;
+-import static io.netty.util.internal.ObjectUtil.checkNotNull;
+-
+-import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectionListener;
+-import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector;
+-
+-import java.util.LinkedHashSet;
+-import java.util.List;
+-
+-import javax.net.ssl.SSLEngine;
+-import javax.net.ssl.SSLException;
+-
+-import io.netty.util.internal.PlatformDependent;
+-import org.eclipse.jetty.alpn.ALPN;
+-
+-abstract class JettyAlpnSslEngine extends JdkSslEngine {
+- private static final boolean available = initAvailable();
+-
+- static boolean isAvailable() {
+- return available;
+- }
+-
+- private static boolean initAvailable() {
+- if (PlatformDependent.javaVersion() <= 8) {
+- try {
+- // Always use bootstrap class loader.
+- Class.forName("sun.security.ssl.ALPNExtension", true, null);
+- return true;
+- } catch (Throwable ignore) {
+- // alpn-boot was not loaded.
+- }
+- }
+- return false;
+- }
+-
+- static JettyAlpnSslEngine newClientEngine(SSLEngine engine,
+- JdkApplicationProtocolNegotiator applicationNegotiator) {
+- return new ClientEngine(engine, applicationNegotiator);
+- }
+-
+- static JettyAlpnSslEngine newServerEngine(SSLEngine engine,
+- JdkApplicationProtocolNegotiator applicationNegotiator) {
+- return new ServerEngine(engine, applicationNegotiator);
+- }
+-
+- private JettyAlpnSslEngine(SSLEngine engine) {
+- super(engine);
+- }
+-
+- private static final class ClientEngine extends JettyAlpnSslEngine {
+- ClientEngine(SSLEngine engine, final JdkApplicationProtocolNegotiator applicationNegotiator) {
+- super(engine);
+- checkNotNull(applicationNegotiator, "applicationNegotiator");
+- final ProtocolSelectionListener protocolListener = checkNotNull(applicationNegotiator
+- .protocolListenerFactory().newListener(this, applicationNegotiator.protocols()),
+- "protocolListener");
+- ALPN.put(engine, new ALPN.ClientProvider() {
+- @Override
+- public List<String> protocols() {
+- return applicationNegotiator.protocols();
+- }
+-
+- @Override
+- public void selected(String protocol) throws SSLException {
+- try {
+- protocolListener.selected(protocol);
+- } catch (Throwable t) {
+- throw toSSLHandshakeException(t);
+- }
+- }
+-
+- @Override
+- public void unsupported() {
+- protocolListener.unsupported();
+- }
+- });
+- }
+-
+- @Override
+- public void closeInbound() throws SSLException {
+- try {
+- ALPN.remove(getWrappedEngine());
+- } finally {
+- super.closeInbound();
+- }
+- }
+-
+- @Override
+- public void closeOutbound() {
+- try {
+- ALPN.remove(getWrappedEngine());
+- } finally {
+- super.closeOutbound();
+- }
+- }
+- }
+-
+- private static final class ServerEngine extends JettyAlpnSslEngine {
+- ServerEngine(SSLEngine engine, final JdkApplicationProtocolNegotiator applicationNegotiator) {
+- super(engine);
+- checkNotNull(applicationNegotiator, "applicationNegotiator");
+- final ProtocolSelector protocolSelector = checkNotNull(applicationNegotiator.protocolSelectorFactory()
+- .newSelector(this, new LinkedHashSet<String>(applicationNegotiator.protocols())),
+- "protocolSelector");
+- ALPN.put(engine, new ALPN.ServerProvider() {
+- @Override
+- public String select(List<String> protocols) throws SSLException {
+- try {
+- return protocolSelector.select(protocols);
+- } catch (Throwable t) {
+- throw toSSLHandshakeException(t);
+- }
+- }
+-
+- @Override
+- public void unsupported() {
+- protocolSelector.unsupported();
+- }
+- });
+- }
+-
+- @Override
+- public void closeInbound() throws SSLException {
+- try {
+- ALPN.remove(getWrappedEngine());
+- } finally {
+- super.closeInbound();
+- }
+- }
+-
+- @Override
+- public void closeOutbound() {
+- try {
+- ALPN.remove(getWrappedEngine());
+- } finally {
+- super.closeOutbound();
+- }
+- }
+- }
+-}
+diff --git a/handler/src/main/java/io/netty/handler/ssl/JettyNpnSslEngine.java b/handler/src/main/java/io/netty/handler/ssl/JettyNpnSslEngine.java
+deleted file mode 100644
+index 77e7366e53..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/JettyNpnSslEngine.java
++++ /dev/null
+@@ -1,122 +0,0 @@
+-/*
+- * Copyright 2014 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- * http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-
+-package io.netty.handler.ssl;
+-
+-import static io.netty.util.internal.ObjectUtil.checkNotNull;
+-import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectionListener;
+-import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector;
+-import io.netty.util.internal.PlatformDependent;
+-
+-import java.util.LinkedHashSet;
+-import java.util.List;
+-
+-import javax.net.ssl.SSLEngine;
+-import javax.net.ssl.SSLException;
+-
+-import org.eclipse.jetty.npn.NextProtoNego;
+-import org.eclipse.jetty.npn.NextProtoNego.ClientProvider;
+-import org.eclipse.jetty.npn.NextProtoNego.ServerProvider;
+-
+-final class JettyNpnSslEngine extends JdkSslEngine {
+- private static boolean available;
+-
+- static boolean isAvailable() {
+- updateAvailability();
+- return available;
+- }
+-
+- private static void updateAvailability() {
+- if (available) {
+- return;
+- }
+- try {
+- // Always use bootstrap class loader.
+- Class.forName("sun.security.ssl.NextProtoNegoExtension", true, null);
+- available = true;
+- } catch (Exception ignore) {
+- // npn-boot was not loaded.
+- }
+- }
+-
+- JettyNpnSslEngine(SSLEngine engine, final JdkApplicationProtocolNegotiator applicationNegotiator, boolean server) {
+- super(engine);
+- checkNotNull(applicationNegotiator, "applicationNegotiator");
+-
+- if (server) {
+- final ProtocolSelectionListener protocolListener = checkNotNull(applicationNegotiator
+- .protocolListenerFactory().newListener(this, applicationNegotiator.protocols()),
+- "protocolListener");
+- NextProtoNego.put(engine, new ServerProvider() {
+- @Override
+- public void unsupported() {
+- protocolListener.unsupported();
+- }
+-
+- @Override
+- public List<String> protocols() {
+- return applicationNegotiator.protocols();
+- }
+-
+- @Override
+- public void protocolSelected(String protocol) {
+- try {
+- protocolListener.selected(protocol);
+- } catch (Throwable t) {
+- PlatformDependent.throwException(t);
+- }
+- }
+- });
+- } else {
+- final ProtocolSelector protocolSelector = checkNotNull(applicationNegotiator.protocolSelectorFactory()
+- .newSelector(this, new LinkedHashSet<String>(applicationNegotiator.protocols())),
+- "protocolSelector");
+- NextProtoNego.put(engine, new ClientProvider() {
+- @Override
+- public boolean supports() {
+- return true;
+- }
+-
+- @Override
+- public void unsupported() {
+- protocolSelector.unsupported();
+- }
+-
+- @Override
+- public String selectProtocol(List<String> protocols) {
+- try {
+- return protocolSelector.select(protocols);
+- } catch (Throwable t) {
+- PlatformDependent.throwException(t);
+- return null;
+- }
+- }
+- });
+- }
+- }
+-
+- @Override
+- public void closeInbound() throws SSLException {
+- NextProtoNego.remove(getWrappedEngine());
+- super.closeInbound();
+- }
+-
+- @Override
+- public void closeOutbound() {
+- NextProtoNego.remove(getWrappedEngine());
+- super.closeOutbound();
+- }
+-}
+diff --git a/pom.xml b/pom.xml
+index db3d7b0d38..bedd6d6903 100644
+--- a/pom.xml
++++ b/pom.xml
+@@ -453,20 +453,6 @@
+ <optional>true</optional>
+ </dependency>
+
+- <!-- SPDY and HTTP/2 - completely optional -->
+- <dependency>
+- <groupId>org.eclipse.jetty.npn</groupId>
+- <artifactId>npn-api</artifactId>
+- <version>1.1.1.v20141010</version>
+- <scope>provided</scope> <!-- Provided by npn-boot -->
+- </dependency>
+- <dependency>
+- <groupId>org.eclipse.jetty.alpn</groupId>
+- <artifactId>alpn-api</artifactId>
+- <version>1.1.2.v20150522</version>
+- <scope>provided</scope> <!-- Provided by alpn-boot -->
+- </dependency>
+-
+ <!-- Google Protocol Buffers - completely optional -->
+ <dependency>
+ <groupId>com.google.protobuf</groupId>
+--
+2.26.2
+
diff --git a/0004-Remove-jetty-ALPN.patch b/0004-Remove-jetty-ALPN.patch
deleted file mode 100644
index 42b5415..0000000
--- a/0004-Remove-jetty-ALPN.patch
+++ /dev/null
@@ -1,217 +0,0 @@
-diff --git a/handler/pom.xml b/handler/pom.xml
-index 69af32a..b9e5596 100644
---- a/handler/pom.xml
-+++ b/handler/pom.xml
-@@ -54,11 +54,6 @@
- <artifactId>bcpkix-jdk15on</artifactId>
- <optional>true</optional>
- </dependency>
-- <dependency>
-- <groupId>org.eclipse.jetty.alpn</groupId>
-- <artifactId>alpn-api</artifactId>
-- <optional>true</optional>
-- </dependency>
- <dependency>
- <groupId>org.mockito</groupId>
- <artifactId>mockito-core</artifactId>
-diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java b/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java
-index 9c4ab9e..5cc1ab7 100644
---- a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java
-+++ b/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java
-@@ -21,7 +21,7 @@ import javax.net.ssl.SSLEngine;
- * The {@link JdkApplicationProtocolNegotiator} to use if you need ALPN and are using {@link SslProvider#JDK}.
- */
- public final class JdkAlpnApplicationProtocolNegotiator extends JdkBaseApplicationProtocolNegotiator {
-- private static final boolean AVAILABLE = JettyAlpnSslEngine.isAvailable();
-+ private static final boolean AVAILABLE = false;
- private static final SslEngineWrapperFactory ALPN_WRAPPER = AVAILABLE ? new AlpnWrapper() : new FailureWrapper();
-
- /**
-@@ -121,10 +121,6 @@ public final class JdkAlpnApplicationProtocolNegotiator extends JdkBaseApplicati
- @Override
- public SSLEngine wrapSslEngine(SSLEngine engine, JdkApplicationProtocolNegotiator applicationNegotiator,
- boolean isServer) {
-- if (JettyAlpnSslEngine.isAvailable()) {
-- return isServer ? JettyAlpnSslEngine.newServerEngine(engine, applicationNegotiator)
-- : JettyAlpnSslEngine.newClientEngine(engine, applicationNegotiator);
-- }
- throw new RuntimeException("Unable to wrap SSLEngine of type " + engine.getClass().getName());
- }
- }
-diff --git a/handler/src/main/java/io/netty/handler/ssl/JettyAlpnSslEngine.java b/handler/src/main/java/io/netty/handler/ssl/JettyAlpnSslEngine.java
-deleted file mode 100644
-index 624719a..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/JettyAlpnSslEngine.java
-+++ /dev/null
-@@ -1,158 +0,0 @@
--/*
-- * Copyright 2014 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
--
--import static io.netty.handler.ssl.SslUtils.toSSLHandshakeException;
--import static io.netty.util.internal.ObjectUtil.checkNotNull;
--
--import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectionListener;
--import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector;
--
--import java.util.LinkedHashSet;
--import java.util.List;
--
--import javax.net.ssl.SSLEngine;
--import javax.net.ssl.SSLException;
--
--import io.netty.util.internal.PlatformDependent;
--import org.eclipse.jetty.alpn.ALPN;
--
--abstract class JettyAlpnSslEngine extends JdkSslEngine {
-- private static final boolean available = initAvailable();
--
-- static boolean isAvailable() {
-- return available;
-- }
--
-- private static boolean initAvailable() {
-- // TODO: Add support for ALPN when using Java9 and still be able to configure it the Netty way.
-- if (PlatformDependent.javaVersion() <= 8) {
-- try {
-- // Always use bootstrap class loader.
-- Class.forName("sun.security.ssl.ALPNExtension", true, null);
-- return true;
-- } catch (Throwable ignore) {
-- // alpn-boot was not loaded.
-- }
-- }
-- return false;
-- }
--
-- static JettyAlpnSslEngine newClientEngine(SSLEngine engine,
-- JdkApplicationProtocolNegotiator applicationNegotiator) {
-- return new ClientEngine(engine, applicationNegotiator);
-- }
--
-- static JettyAlpnSslEngine newServerEngine(SSLEngine engine,
-- JdkApplicationProtocolNegotiator applicationNegotiator) {
-- return new ServerEngine(engine, applicationNegotiator);
-- }
--
-- private JettyAlpnSslEngine(SSLEngine engine) {
-- super(engine);
-- }
--
-- private static final class ClientEngine extends JettyAlpnSslEngine {
-- ClientEngine(SSLEngine engine, final JdkApplicationProtocolNegotiator applicationNegotiator) {
-- super(engine);
-- checkNotNull(applicationNegotiator, "applicationNegotiator");
-- final ProtocolSelectionListener protocolListener = checkNotNull(applicationNegotiator
-- .protocolListenerFactory().newListener(this, applicationNegotiator.protocols()),
-- "protocolListener");
-- ALPN.put(engine, new ALPN.ClientProvider() {
-- @Override
-- public List<String> protocols() {
-- return applicationNegotiator.protocols();
-- }
--
-- @Override
-- public void selected(String protocol) throws SSLException {
-- try {
-- protocolListener.selected(protocol);
-- } catch (Throwable t) {
-- throw toSSLHandshakeException(t);
-- }
-- }
--
-- @Override
-- public void unsupported() {
-- protocolListener.unsupported();
-- }
-- });
-- }
--
-- @Override
-- public void closeInbound() throws SSLException {
-- try {
-- ALPN.remove(getWrappedEngine());
-- } finally {
-- super.closeInbound();
-- }
-- }
--
-- @Override
-- public void closeOutbound() {
-- try {
-- ALPN.remove(getWrappedEngine());
-- } finally {
-- super.closeOutbound();
-- }
-- }
-- }
--
-- private static final class ServerEngine extends JettyAlpnSslEngine {
-- ServerEngine(SSLEngine engine, final JdkApplicationProtocolNegotiator applicationNegotiator) {
-- super(engine);
-- checkNotNull(applicationNegotiator, "applicationNegotiator");
-- final ProtocolSelector protocolSelector = checkNotNull(applicationNegotiator.protocolSelectorFactory()
-- .newSelector(this, new LinkedHashSet<String>(applicationNegotiator.protocols())),
-- "protocolSelector");
-- ALPN.put(engine, new ALPN.ServerProvider() {
-- @Override
-- public String select(List<String> protocols) throws SSLException {
-- try {
-- return protocolSelector.select(protocols);
-- } catch (Throwable t) {
-- throw toSSLHandshakeException(t);
-- }
-- }
--
-- @Override
-- public void unsupported() {
-- protocolSelector.unsupported();
-- }
-- });
-- }
--
-- @Override
-- public void closeInbound() throws SSLException {
-- try {
-- ALPN.remove(getWrappedEngine());
-- } finally {
-- super.closeInbound();
-- }
-- }
--
-- @Override
-- public void closeOutbound() {
-- try {
-- ALPN.remove(getWrappedEngine());
-- } finally {
-- super.closeOutbound();
-- }
-- }
-- }
--}
-diff --git a/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java b/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java
-index e32fa0d..a8014e5 100644
---- a/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java
-+++ b/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java
-@@ -62,7 +62,7 @@ public class JdkSslEngineTest extends SSLEngineTest {
- ALPN_DEFAULT {
- @Override
- boolean isAvailable() {
-- return JettyAlpnSslEngine.isAvailable();
-+ return false;
- }
-
- @Override
diff --git a/0001-Remove-OpenSSL-parts-depending-on-tcnative.patch b/0004-Remove-optional-dep-tcnative.patch
similarity index 54%
rename from 0001-Remove-OpenSSL-parts-depending-on-tcnative.patch
rename to 0004-Remove-optional-dep-tcnative.patch
index aee0650..6ed11bd 100644
--- a/0001-Remove-OpenSSL-parts-depending-on-tcnative.patch
+++ b/0004-Remove-optional-dep-tcnative.patch
@@ -1,108 +1,94 @@
-From 39b320920d3473d8cbc94d4a35dad37fa236e278 Mon Sep 17 00:00:00 2001
-From: Severin Gehwolf <sgehwolf(a)redhat.com>
-Date: Thu, 20 Oct 2016 15:54:52 +0200
-Subject: [PATCH 1/3] Remove OpenSSL parts depending on tcnative.
+From c60f3b8d7ca0575bba15682a329dced786f898da Mon Sep 17 00:00:00 2001
+From: Mat Booth <mat.booth(a)redhat.com>
+Date: Mon, 7 Sep 2020 13:41:44 +0100
+Subject: [PATCH 4/5] Remove optional dep tcnative
---
- handler/pom.xml | 6 -
- .../main/java/io/netty/handler/ssl/OpenSsl.java | 503 -----
- .../handler/ssl/OpenSslCertificateException.java | 79 -
- .../io/netty/handler/ssl/OpenSslClientContext.java | 211 --
- .../java/io/netty/handler/ssl/OpenSslContext.java | 58 -
- .../java/io/netty/handler/ssl/OpenSslEngine.java | 40 -
- .../io/netty/handler/ssl/OpenSslEngineMap.java | 35 -
- .../ssl/OpenSslExtendedKeyMaterialManager.java | 40 -
- .../handler/ssl/OpenSslKeyMaterialManager.java | 179 --
- .../io/netty/handler/ssl/OpenSslServerContext.java | 373 ----
- .../handler/ssl/OpenSslServerSessionContext.java | 124 --
- .../netty/handler/ssl/OpenSslSessionContext.java | 137 --
- .../io/netty/handler/ssl/OpenSslSessionStats.java | 253 ---
- .../netty/handler/ssl/OpenSslSessionTicketKey.java | 78 -
- .../ssl/ReferenceCountedOpenSslClientContext.java | 298 ---
- .../ssl/ReferenceCountedOpenSslContext.java | 867 ---------
- .../handler/ssl/ReferenceCountedOpenSslEngine.java | 2037 --------------------
- .../ssl/ReferenceCountedOpenSslServerContext.java | 239 ---
- .../main/java/io/netty/handler/ssl/SslContext.java | 30 +-
- .../main/java/io/netty/handler/ssl/SslHandler.java | 47 +-
- .../netty/handler/ssl/ocsp/OcspClientHandler.java | 65 -
- .../io/netty/handler/ssl/ocsp/package-info.java | 23 -
- .../handler/ssl/JdkOpenSslEngineInteroptTest.java | 108 --
- .../ssl/OpenSslCertificateExceptionTest.java | 49 -
- .../handler/ssl/OpenSslClientContextTest.java | 38 -
- .../io/netty/handler/ssl/OpenSslEngineTest.java | 661 -------
- .../ssl/OpenSslJdkSslEngineInteroptTest.java | 114 --
- .../ssl/OpenSslRenegotiateSmallBIOTest.java | 23 -
- .../netty/handler/ssl/OpenSslRenegotiateTest.java | 36 -
- .../handler/ssl/OpenSslServerContextTest.java | 39 -
- .../io/netty/handler/ssl/OpenSslTestUtils.java | 27 -
- .../java/io/netty/handler/ssl/PemEncodedTest.java | 95 -
- .../ssl/ReferenceCountedOpenSslEngineTest.java | 57 -
- .../java/io/netty/handler/ssl/SniClientTest.java | 161 --
- .../java/io/netty/handler/ssl/SniHandlerTest.java | 496 -----
- .../netty/handler/ssl/SslContextBuilderTest.java | 132 --
- .../java/io/netty/handler/ssl/SslErrorTest.java | 255 ---
- .../java/io/netty/handler/ssl/SslHandlerTest.java | 58 +-
- .../java/io/netty/handler/ssl/ocsp/OcspTest.java | 501 -----
- 39 files changed, 10 insertions(+), 8562 deletions(-)
+ handler/pom.xml | 6 -
+ .../handler/ssl/CipherSuiteConverter.java | 494 ----
+ .../ssl/DefaultOpenSslKeyMaterial.java | 126 -
+ .../java/io/netty/handler/ssl/OpenSsl.java | 610 ----
+ .../OpenSslCachingKeyMaterialProvider.java | 79 -
+ .../OpenSslCachingX509KeyManagerFactory.java | 81 -
+ .../ssl/OpenSslCertificateException.java | 81 -
+ .../handler/ssl/OpenSslClientContext.java | 208 --
+ .../io/netty/handler/ssl/OpenSslContext.java | 58 -
+ .../io/netty/handler/ssl/OpenSslEngine.java | 41 -
+ .../netty/handler/ssl/OpenSslEngineMap.java | 35 -
+ .../ssl/OpenSslKeyMaterialManager.java | 127 -
+ .../ssl/OpenSslKeyMaterialProvider.java | 154 -
+ .../netty/handler/ssl/OpenSslPrivateKey.java | 191 --
+ .../handler/ssl/OpenSslPrivateKeyMethod.java | 62 -
+ .../handler/ssl/OpenSslServerContext.java | 367 ---
+ .../ssl/OpenSslServerSessionContext.java | 124 -
+ .../handler/ssl/OpenSslSessionContext.java | 158 --
+ .../handler/ssl/OpenSslSessionStats.java | 253 --
+ .../handler/ssl/OpenSslSessionTicketKey.java | 78 -
+ ...OpenSslTlsv13X509ExtendedTrustManager.java | 240 --
+ .../ssl/OpenSslX509KeyManagerFactory.java | 413 ---
+ .../ReferenceCountedOpenSslClientContext.java | 343 ---
+ .../ssl/ReferenceCountedOpenSslContext.java | 968 -------
+ .../ssl/ReferenceCountedOpenSslEngine.java | 2467 -----------------
+ .../ReferenceCountedOpenSslServerContext.java | 286 --
+ .../java/io/netty/handler/ssl/SslContext.java | 30 +-
+ .../java/io/netty/handler/ssl/SslHandler.java | 49 +-
+ .../handler/ssl/SslMasterKeyHandler.java | 3 -
+ .../io/netty/handler/ssl/SslProvider.java | 14 +-
+ .../handler/ssl/ocsp/OcspClientHandler.java | 61 -
+ .../netty/handler/ssl/ocsp/package-info.java | 23 -
+ pom.xml | 10 -
+ 33 files changed, 3 insertions(+), 8237 deletions(-)
+ delete mode 100644 handler/src/main/java/io/netty/handler/ssl/CipherSuiteConverter.java
+ delete mode 100644 handler/src/main/java/io/netty/handler/ssl/DefaultOpenSslKeyMaterial.java
delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSsl.java
+ delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslCachingKeyMaterialProvider.java
+ delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslCachingX509KeyManagerFactory.java
delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslCertificateException.java
delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslClientContext.java
delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslContext.java
delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslEngine.java
delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslEngineMap.java
- delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslExtendedKeyMaterialManager.java
delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialManager.java
+ delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialProvider.java
+ delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslPrivateKey.java
+ delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslPrivateKeyMethod.java
delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslServerContext.java
delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslServerSessionContext.java
delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslSessionContext.java
delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslSessionStats.java
delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslSessionTicketKey.java
+ delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslTlsv13X509ExtendedTrustManager.java
+ delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslX509KeyManagerFactory.java
delete mode 100644 handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslClientContext.java
delete mode 100644 handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslContext.java
delete mode 100644 handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngine.java
delete mode 100644 handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslServerContext.java
delete mode 100644 handler/src/main/java/io/netty/handler/ssl/ocsp/OcspClientHandler.java
delete mode 100644 handler/src/main/java/io/netty/handler/ssl/ocsp/package-info.java
- delete mode 100644 handler/src/test/java/io/netty/handler/ssl/JdkOpenSslEngineInteroptTest.java
- delete mode 100644 handler/src/test/java/io/netty/handler/ssl/OpenSslCertificateExceptionTest.java
- delete mode 100644 handler/src/test/java/io/netty/handler/ssl/OpenSslClientContextTest.java
- delete mode 100644 handler/src/test/java/io/netty/handler/ssl/OpenSslEngineTest.java
- delete mode 100644 handler/src/test/java/io/netty/handler/ssl/OpenSslJdkSslEngineInteroptTest.java
- delete mode 100644 handler/src/test/java/io/netty/handler/ssl/OpenSslRenegotiateSmallBIOTest.java
- delete mode 100644 handler/src/test/java/io/netty/handler/ssl/OpenSslRenegotiateTest.java
- delete mode 100644 handler/src/test/java/io/netty/handler/ssl/OpenSslServerContextTest.java
- delete mode 100644 handler/src/test/java/io/netty/handler/ssl/OpenSslTestUtils.java
- delete mode 100644 handler/src/test/java/io/netty/handler/ssl/PemEncodedTest.java
- delete mode 100644 handler/src/test/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngineTest.java
- delete mode 100644 handler/src/test/java/io/netty/handler/ssl/SniClientTest.java
- delete mode 100644 handler/src/test/java/io/netty/handler/ssl/SniHandlerTest.java
- delete mode 100644 handler/src/test/java/io/netty/handler/ssl/SslContextBuilderTest.java
- delete mode 100644 handler/src/test/java/io/netty/handler/ssl/SslErrorTest.java
- delete mode 100644 handler/src/test/java/io/netty/handler/ssl/ocsp/OcspTest.java
diff --git a/handler/pom.xml b/handler/pom.xml
-index 7535c45..d0ed1bc 100644
+index be8206dc89..e28cc6f7af 100644
--- a/handler/pom.xml
+++ b/handler/pom.xml
-@@ -50,12 +50,6 @@
+@@ -60,12 +60,6 @@
+ <artifactId>netty-codec</artifactId>
<version>${project.version}</version>
</dependency>
- <dependency>
+- <dependency>
- <groupId>${project.groupId}</groupId>
- <artifactId>${tcnative.artifactId}</artifactId>
- <classifier>${tcnative.classifier}</classifier>
- <optional>true</optional>
- </dependency>
-- <dependency>
+ <dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
- <optional>true</optional>
-diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSsl.java b/handler/src/main/java/io/netty/handler/ssl/OpenSsl.java
+diff --git a/handler/src/main/java/io/netty/handler/ssl/CipherSuiteConverter.java b/handler/src/main/java/io/netty/handler/ssl/CipherSuiteConverter.java
deleted file mode 100644
-index d2f091a..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/OpenSsl.java
+index 94e951f7f5..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/CipherSuiteConverter.java
+++ /dev/null
-@@ -1,503 +0,0 @@
+@@ -1,494 +0,0 @@
-/*
- * Copyright 2014 The Netty Project
- *
@@ -121,499 +107,490 @@ index d2f091a..0000000
-
-package io.netty.handler.ssl;
-
--import io.netty.buffer.ByteBuf;
--import io.netty.handler.ssl.util.SelfSignedCertificate;
--import io.netty.util.ReferenceCountUtil;
--import io.netty.util.ReferenceCounted;
--import io.netty.util.internal.NativeLibraryLoader;
--import io.netty.util.internal.SystemPropertyUtil;
+-import io.netty.util.internal.PlatformDependent;
-import io.netty.util.internal.logging.InternalLogger;
-import io.netty.util.internal.logging.InternalLoggerFactory;
--import io.netty.internal.tcnative.Buffer;
--import io.netty.internal.tcnative.Library;
--import io.netty.internal.tcnative.SSL;
--import io.netty.internal.tcnative.SSLContext;
-
--import java.security.AccessController;
--import java.security.PrivilegedAction;
-import java.util.Collections;
--import java.util.LinkedHashSet;
--import java.util.Locale;
--import java.util.Set;
+-import java.util.HashMap;
+-import java.util.Map;
+-import java.util.concurrent.ConcurrentMap;
+-import java.util.regex.Matcher;
+-import java.util.regex.Pattern;
+-
+-import static java.util.Collections.singletonMap;
-
-/**
-- * Tells if <a href="http://netty.io/wiki/forked-tomcat-native.html">{@code netty-tcnative}</a> and its OpenSSL support
-- * are available.
+- * Converts a Java cipher suite string to an OpenSSL cipher suite string and vice versa.
+- *
+- * @see <a href="http://en.wikipedia.org/wiki/Cipher_suite">Wikipedia page about cipher suite</a>
- */
--public final class OpenSsl {
+-final class CipherSuiteConverter {
-
-- private static final InternalLogger logger = InternalLoggerFactory.getInstance(OpenSsl.class);
-- private static final String LINUX = "linux";
-- private static final String UNKNOWN = "unknown";
-- private static final Throwable UNAVAILABILITY_CAUSE;
+- private static final InternalLogger logger = InternalLoggerFactory.getInstance(CipherSuiteConverter.class);
-
-- static final Set<String> AVAILABLE_CIPHER_SUITES;
-- private static final Set<String> AVAILABLE_OPENSSL_CIPHER_SUITES;
-- private static final Set<String> AVAILABLE_JAVA_CIPHER_SUITES;
-- private static final boolean SUPPORTS_KEYMANAGER_FACTORY;
-- private static final boolean SUPPORTS_HOSTNAME_VALIDATION;
-- private static final boolean USE_KEYMANAGER_FACTORY;
-- private static final boolean SUPPORTS_OCSP;
+- /**
+- * A_B_WITH_C_D, where:
+- *
+- * A - TLS or SSL (protocol)
+- * B - handshake algorithm (key exchange and authentication algorithms to be precise)
+- * C - bulk cipher
+- * D - HMAC algorithm
+- *
+- * This regular expression assumes that:
+- *
+- * 1) A is always TLS or SSL, and
+- * 2) D is always a single word.
+- */
+- private static final Pattern JAVA_CIPHERSUITE_PATTERN =
+- Pattern.compile("^(?:TLS|SSL)_((?:(?!_WITH_).)+)_WITH_(.*)_(.*)$");
+-
+- /**
+- * A-B-C, where:
+- *
+- * A - handshake algorithm (key exchange and authentication algorithms to be precise)
+- * B - bulk cipher
+- * C - HMAC algorithm
+- *
+- * This regular expression assumes that:
+- *
+- * 1) A has some deterministic pattern as shown below, and
+- * 2) C is always a single word
+- */
+- private static final Pattern OPENSSL_CIPHERSUITE_PATTERN =
+- // Be very careful not to break the indentation while editing.
+- Pattern.compile(
+- "^(?:(" + // BEGIN handshake algorithm
+- "(?:(?:EXP-)?" +
+- "(?:" +
+- "(?:DHE|EDH|ECDH|ECDHE|SRP|RSA)-(?:DSS|RSA|ECDSA|PSK)|" +
+- "(?:ADH|AECDH|KRB5|PSK|SRP)" +
+- ')' +
+- ")|" +
+- "EXP" +
+- ")-)?" + // END handshake algorithm
+- "(.*)-(.*)$");
+-
+- private static final Pattern JAVA_AES_CBC_PATTERN = Pattern.compile("^(AES)_([0-9]+)_CBC$");
+- private static final Pattern JAVA_AES_PATTERN = Pattern.compile("^(AES)_([0-9]+)_(.*)$");
+- private static final Pattern OPENSSL_AES_CBC_PATTERN = Pattern.compile("^(AES)([0-9]+)$");
+- private static final Pattern OPENSSL_AES_PATTERN = Pattern.compile("^(AES)([0-9]+)-(.*)$");
-
-- // Protocols
-- static final String PROTOCOL_SSL_V2_HELLO = "SSLv2Hello";
-- static final String PROTOCOL_SSL_V2 = "SSLv2";
-- static final String PROTOCOL_SSL_V3 = "SSLv3";
-- static final String PROTOCOL_TLS_V1 = "TLSv1";
-- static final String PROTOCOL_TLS_V1_1 = "TLSv1.1";
-- static final String PROTOCOL_TLS_V1_2 = "TLSv1.2";
+- /**
+- * Java-to-OpenSSL cipher suite conversion map
+- * Note that the Java cipher suite has the protocol prefix (TLS_, SSL_)
+- */
+- private static final ConcurrentMap<String, String> j2o = PlatformDependent.newConcurrentHashMap();
-
-- static final Set<String> SUPPORTED_PROTOCOLS_SET;
+- /**
+- * OpenSSL-to-Java cipher suite conversion map.
+- * Note that one OpenSSL cipher suite can be converted to more than one Java cipher suites because
+- * a Java cipher suite has the protocol name prefix (TLS_, SSL_)
+- */
+- private static final ConcurrentMap<String, Map<String, String>> o2j = PlatformDependent.newConcurrentHashMap();
+-
+- private static final Map<String, String> j2oTls13;
+- private static final Map<String, Map<String, String>> o2jTls13;
-
- static {
-- Throwable cause = null;
+- Map<String, String> j2oTls13Map = new HashMap<String, String>();
+- j2oTls13Map.put("TLS_AES_128_GCM_SHA256", "AEAD-AES128-GCM-SHA256");
+- j2oTls13Map.put("TLS_AES_256_GCM_SHA384", "AEAD-AES256-GCM-SHA384");
+- j2oTls13Map.put("TLS_CHACHA20_POLY1305_SHA256", "AEAD-CHACHA20-POLY1305-SHA256");
+- j2oTls13 = Collections.unmodifiableMap(j2oTls13Map);
+-
+- Map<String, Map<String, String>> o2jTls13Map = new HashMap<String, Map<String, String>>();
+- o2jTls13Map.put("TLS_AES_128_GCM_SHA256", singletonMap("TLS", "TLS_AES_128_GCM_SHA256"));
+- o2jTls13Map.put("TLS_AES_256_GCM_SHA384", singletonMap("TLS", "TLS_AES_256_GCM_SHA384"));
+- o2jTls13Map.put("TLS_CHACHA20_POLY1305_SHA256", singletonMap("TLS", "TLS_CHACHA20_POLY1305_SHA256"));
+- o2jTls13Map.put("AEAD-AES128-GCM-SHA256", singletonMap("TLS", "TLS_AES_128_GCM_SHA256"));
+- o2jTls13Map.put("AEAD-AES256-GCM-SHA384", singletonMap("TLS", "TLS_AES_256_GCM_SHA384"));
+- o2jTls13Map.put("AEAD-CHACHA20-POLY1305-SHA256", singletonMap("TLS", "TLS_CHACHA20_POLY1305_SHA256"));
+- o2jTls13 = Collections.unmodifiableMap(o2jTls13Map);
+- }
-
-- // Test if netty-tcnative is in the classpath first.
-- try {
-- Class.forName("io.netty.internal.tcnative.SSL", false, OpenSsl.class.getClassLoader());
-- } catch (ClassNotFoundException t) {
-- cause = t;
-- logger.debug(
-- "netty-tcnative not in the classpath; " +
-- OpenSslEngine.class.getSimpleName() + " will be unavailable.");
+- /**
+- * Clears the cache for testing purpose.
+- */
+- static void clearCache() {
+- j2o.clear();
+- o2j.clear();
+- }
+-
+- /**
+- * Tests if the specified key-value pair has been cached in Java-to-OpenSSL cache.
+- */
+- static boolean isJ2OCached(String key, String value) {
+- return value.equals(j2o.get(key));
+- }
+-
+- /**
+- * Tests if the specified key-value pair has been cached in OpenSSL-to-Java cache.
+- */
+- static boolean isO2JCached(String key, String protocol, String value) {
+- Map<String, String> p2j = o2j.get(key);
+- if (p2j == null) {
+- return false;
+- } else {
+- return value.equals(p2j.get(protocol));
- }
+- }
-
-- // If in the classpath, try to load the native library and initialize netty-tcnative.
-- if (cause == null) {
-- try {
-- // The JNI library was not already loaded. Load it now.
-- loadTcNative();
-- } catch (Throwable t) {
-- cause = t;
-- logger.debug(
-- "Failed to load netty-tcnative; " +
-- OpenSslEngine.class.getSimpleName() + " will be unavailable, unless the " +
-- "application has already loaded the symbols by some other means. " +
-- "See http://netty.io/wiki/forked-tomcat-native.html for more information.", t);
-- }
+- /**
+- * Converts the specified Java cipher suite to its corresponding OpenSSL cipher suite name.
+- *
+- * @return {@code null} if the conversion has failed
+- */
+- static String toOpenSsl(String javaCipherSuite, boolean boringSSL) {
+- String converted = j2o.get(javaCipherSuite);
+- if (converted != null) {
+- return converted;
+- }
+- return cacheFromJava(javaCipherSuite, boringSSL);
+- }
-
-- try {
-- initializeTcNative();
--
-- // The library was initialized successfully. If loading the library failed above,
-- // reset the cause now since it appears that the library was loaded by some other
-- // means.
-- cause = null;
-- } catch (Throwable t) {
-- if (cause == null) {
-- cause = t;
-- }
-- logger.debug(
-- "Failed to initialize netty-tcnative; " +
-- OpenSslEngine.class.getSimpleName() + " will be unavailable. " +
-- "See http://netty.io/wiki/forked-tomcat-native.html for more information.", t);
-- }
+- private static String cacheFromJava(String javaCipherSuite, boolean boringSSL) {
+- String converted = j2oTls13.get(javaCipherSuite);
+- if (converted != null) {
+- return boringSSL ? converted : javaCipherSuite;
- }
-
-- UNAVAILABILITY_CAUSE = cause;
+- String openSslCipherSuite = toOpenSslUncached(javaCipherSuite, boringSSL);
+- if (openSslCipherSuite == null) {
+- return null;
+- }
-
-- if (cause == null) {
-- logger.debug("netty-tcnative using native library: {}", SSL.versionString());
+- // Cache the mapping.
+- j2o.putIfAbsent(javaCipherSuite, openSslCipherSuite);
-
-- final Set<String> availableOpenSslCipherSuites = new LinkedHashSet<String>(128);
-- boolean supportsKeyManagerFactory = false;
-- boolean useKeyManagerFactory = false;
-- boolean supportsHostNameValidation = false;
-- try {
-- final long sslCtx = SSLContext.make(SSL.SSL_PROTOCOL_ALL, SSL.SSL_MODE_SERVER);
-- long certBio = 0;
-- SelfSignedCertificate cert = null;
-- try {
-- SSLContext.setCipherSuite(sslCtx, "ALL");
-- final long ssl = SSL.newSSL(sslCtx, true);
-- try {
-- for (String c: SSL.getCiphers(ssl)) {
-- // Filter out bad input.
-- if (c == null || c.isEmpty() || availableOpenSslCipherSuites.contains(c)) {
-- continue;
-- }
-- availableOpenSslCipherSuites.add(c);
-- }
-- try {
-- SSL.setHostNameValidation(ssl, 0, "netty.io");
-- supportsHostNameValidation = true;
-- } catch (Throwable ignore) {
-- logger.debug("Hostname Verification not supported.");
-- }
-- try {
-- cert = new SelfSignedCertificate();
-- certBio = ReferenceCountedOpenSslContext.toBIO(cert.cert());
-- SSL.setCertificateChainBio(ssl, certBio, false);
-- supportsKeyManagerFactory = true;
-- try {
-- useKeyManagerFactory = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
-- @Override
-- public Boolean run() {
-- return SystemPropertyUtil.getBoolean(
-- "io.netty.handler.ssl.openssl.useKeyManagerFactory", true);
-- }
-- });
-- } catch (Throwable ignore) {
-- logger.debug("Failed to get useKeyManagerFactory system property.");
-- }
-- } catch (Throwable ignore) {
-- logger.debug("KeyManagerFactory not supported.");
-- }
-- } finally {
-- SSL.freeSSL(ssl);
-- if (certBio != 0) {
-- SSL.freeBIO(certBio);
-- }
-- if (cert != null) {
-- cert.delete();
-- }
-- }
-- } finally {
-- SSLContext.free(sslCtx);
-- }
-- } catch (Exception e) {
-- logger.warn("Failed to get the list of available OpenSSL cipher suites.", e);
-- }
-- AVAILABLE_OPENSSL_CIPHER_SUITES = Collections.unmodifiableSet(availableOpenSslCipherSuites);
+- // Cache the reverse mapping after stripping the protocol prefix (TLS_ or SSL_)
+- final String javaCipherSuiteSuffix = javaCipherSuite.substring(4);
+- Map<String, String> p2j = new HashMap<String, String>(4);
+- p2j.put("", javaCipherSuiteSuffix);
+- p2j.put("SSL", "SSL_" + javaCipherSuiteSuffix);
+- p2j.put("TLS", "TLS_" + javaCipherSuiteSuffix);
+- o2j.put(openSslCipherSuite, p2j);
-
-- final Set<String> availableJavaCipherSuites = new LinkedHashSet<String>(
-- AVAILABLE_OPENSSL_CIPHER_SUITES.size() * 2);
-- for (String cipher: AVAILABLE_OPENSSL_CIPHER_SUITES) {
-- // Included converted but also openssl cipher name
-- availableJavaCipherSuites.add(CipherSuiteConverter.toJava(cipher, "TLS"));
-- availableJavaCipherSuites.add(CipherSuiteConverter.toJava(cipher, "SSL"));
-- }
-- AVAILABLE_JAVA_CIPHER_SUITES = Collections.unmodifiableSet(availableJavaCipherSuites);
+- logger.debug("Cipher suite mapping: {} => {}", javaCipherSuite, openSslCipherSuite);
-
-- final Set<String> availableCipherSuites = new LinkedHashSet<String>(
-- AVAILABLE_OPENSSL_CIPHER_SUITES.size() + AVAILABLE_JAVA_CIPHER_SUITES.size());
-- availableCipherSuites.addAll(AVAILABLE_OPENSSL_CIPHER_SUITES);
-- availableCipherSuites.addAll(AVAILABLE_JAVA_CIPHER_SUITES);
+- return openSslCipherSuite;
+- }
-
-- AVAILABLE_CIPHER_SUITES = availableCipherSuites;
-- SUPPORTS_KEYMANAGER_FACTORY = supportsKeyManagerFactory;
-- SUPPORTS_HOSTNAME_VALIDATION = supportsHostNameValidation;
-- USE_KEYMANAGER_FACTORY = useKeyManagerFactory;
+- static String toOpenSslUncached(String javaCipherSuite, boolean boringSSL) {
+- String converted = j2oTls13.get(javaCipherSuite);
+- if (converted != null) {
+- return boringSSL ? converted : javaCipherSuite;
+- }
-
-- Set<String> protocols = new LinkedHashSet<String>(6);
-- // Seems like there is no way to explicitly disable SSLv2Hello in openssl so it is always enabled
-- protocols.add(PROTOCOL_SSL_V2_HELLO);
-- if (doesSupportProtocol(SSL.SSL_PROTOCOL_SSLV2)) {
-- protocols.add(PROTOCOL_SSL_V2);
-- }
-- if (doesSupportProtocol(SSL.SSL_PROTOCOL_SSLV3)) {
-- protocols.add(PROTOCOL_SSL_V3);
-- }
-- if (doesSupportProtocol(SSL.SSL_PROTOCOL_TLSV1)) {
-- protocols.add(PROTOCOL_TLS_V1);
-- }
-- if (doesSupportProtocol(SSL.SSL_PROTOCOL_TLSV1_1)) {
-- protocols.add(PROTOCOL_TLS_V1_1);
-- }
-- if (doesSupportProtocol(SSL.SSL_PROTOCOL_TLSV1_2)) {
-- protocols.add(PROTOCOL_TLS_V1_2);
-- }
+- Matcher m = JAVA_CIPHERSUITE_PATTERN.matcher(javaCipherSuite);
+- if (!m.matches()) {
+- return null;
+- }
-
-- SUPPORTED_PROTOCOLS_SET = Collections.unmodifiableSet(protocols);
-- SUPPORTS_OCSP = doesSupportOcsp();
+- String handshakeAlgo = toOpenSslHandshakeAlgo(m.group(1));
+- String bulkCipher = toOpenSslBulkCipher(m.group(2));
+- String hmacAlgo = toOpenSslHmacAlgo(m.group(3));
+- if (handshakeAlgo.isEmpty()) {
+- return bulkCipher + '-' + hmacAlgo;
+- } else if (bulkCipher.contains("CHACHA20")) {
+- return handshakeAlgo + '-' + bulkCipher;
- } else {
-- AVAILABLE_OPENSSL_CIPHER_SUITES = Collections.emptySet();
-- AVAILABLE_JAVA_CIPHER_SUITES = Collections.emptySet();
-- AVAILABLE_CIPHER_SUITES = Collections.emptySet();
-- SUPPORTS_KEYMANAGER_FACTORY = false;
-- SUPPORTS_HOSTNAME_VALIDATION = false;
-- USE_KEYMANAGER_FACTORY = false;
-- SUPPORTED_PROTOCOLS_SET = Collections.emptySet();
-- SUPPORTS_OCSP = false;
+- return handshakeAlgo + '-' + bulkCipher + '-' + hmacAlgo;
- }
- }
-
-- private static boolean doesSupportOcsp() {
-- boolean supportsOcsp = false;
-- if (version() >= 0x10002000L) {
-- long sslCtx = -1;
-- try {
-- sslCtx = SSLContext.make(SSL.SSL_PROTOCOL_TLSV1_2, SSL.SSL_MODE_SERVER);
-- SSLContext.enableOcsp(sslCtx, false);
-- supportsOcsp = true;
-- } catch (Exception ignore) {
-- // ignore
-- } finally {
-- if (sslCtx != -1) {
-- SSLContext.free(sslCtx);
-- }
+- private static String toOpenSslHandshakeAlgo(String handshakeAlgo) {
+- final boolean export = handshakeAlgo.endsWith("_EXPORT");
+- if (export) {
+- handshakeAlgo = handshakeAlgo.substring(0, handshakeAlgo.length() - 7);
+- }
+-
+- if ("RSA".equals(handshakeAlgo)) {
+- handshakeAlgo = "";
+- } else if (handshakeAlgo.endsWith("_anon")) {
+- handshakeAlgo = 'A' + handshakeAlgo.substring(0, handshakeAlgo.length() - 5);
+- }
+-
+- if (export) {
+- if (handshakeAlgo.isEmpty()) {
+- handshakeAlgo = "EXP";
+- } else {
+- handshakeAlgo = "EXP-" + handshakeAlgo;
- }
- }
-- return supportsOcsp;
+-
+- return handshakeAlgo.replace('_', '-');
- }
-- private static boolean doesSupportProtocol(int protocol) {
-- long sslCtx = -1;
-- try {
-- sslCtx = SSLContext.make(protocol, SSL.SSL_MODE_COMBINED);
-- return true;
-- } catch (Exception ignore) {
-- return false;
-- } finally {
-- if (sslCtx != -1) {
-- SSLContext.free(sslCtx);
+-
+- private static String toOpenSslBulkCipher(String bulkCipher) {
+- if (bulkCipher.startsWith("AES_")) {
+- Matcher m = JAVA_AES_CBC_PATTERN.matcher(bulkCipher);
+- if (m.matches()) {
+- return m.replaceFirst("$1$2");
+- }
+-
+- m = JAVA_AES_PATTERN.matcher(bulkCipher);
+- if (m.matches()) {
+- return m.replaceFirst("$1$2-$3");
- }
- }
-- }
-
-- /**
-- * Returns {@code true} if and only if
-- * <a href="http://netty.io/wiki/forked-tomcat-native.html">{@code netty-tcnative}</a> and its OpenSSL support
-- * are available.
-- */
-- public static boolean isAvailable() {
-- return UNAVAILABILITY_CAUSE == null;
-- }
+- if ("3DES_EDE_CBC".equals(bulkCipher)) {
+- return "DES-CBC3";
+- }
-
-- /**
-- * Returns {@code true} if the used version of openssl supports
-- * <a href="https://tools.ietf.org/html/rfc7301">ALPN</a>.
-- */
-- public static boolean isAlpnSupported() {
-- return version() >= 0x10002000L;
-- }
+- if ("RC4_128".equals(bulkCipher) || "RC4_40".equals(bulkCipher)) {
+- return "RC4";
+- }
-
-- /**
-- * Returns {@code true} if the used version of OpenSSL supports OCSP stapling.
-- */
-- public static boolean isOcspSupported() {
-- return SUPPORTS_OCSP;
-- }
+- if ("DES40_CBC".equals(bulkCipher) || "DES_CBC_40".equals(bulkCipher)) {
+- return "DES-CBC";
+- }
-
-- /**
-- * Returns the version of the used available OpenSSL library or {@code -1} if {@link #isAvailable()}
-- * returns {@code false}.
-- */
-- public static int version() {
-- return isAvailable() ? SSL.version() : -1;
+- if ("RC2_CBC_40".equals(bulkCipher)) {
+- return "RC2-CBC";
+- }
+-
+- return bulkCipher.replace('_', '-');
- }
-
-- /**
-- * Returns the version string of the used available OpenSSL library or {@code null} if {@link #isAvailable()}
-- * returns {@code false}.
-- */
-- public static String versionString() {
-- return isAvailable() ? SSL.versionString() : null;
+- private static String toOpenSslHmacAlgo(String hmacAlgo) {
+- // Java and OpenSSL use the same algorithm names for:
+- //
+- // * SHA
+- // * SHA256
+- // * MD5
+- //
+- return hmacAlgo;
- }
-
- /**
-- * Ensure that <a href="http://netty.io/wiki/forked-tomcat-native.html">{@code netty-tcnative}</a> and
-- * its OpenSSL support are available.
-- *
-- * @throws UnsatisfiedLinkError if unavailable
+- * Convert from OpenSSL cipher suite name convention to java cipher suite name convention.
+- * @param openSslCipherSuite An OpenSSL cipher suite name.
+- * @param protocol The cryptographic protocol (i.e. SSL, TLS, ...).
+- * @return The translated cipher suite name according to java conventions. This will not be {@code null}.
- */
-- public static void ensureAvailability() {
-- if (UNAVAILABILITY_CAUSE != null) {
-- throw (Error) new UnsatisfiedLinkError(
-- "failed to load the required native library").initCause(UNAVAILABILITY_CAUSE);
+- static String toJava(String openSslCipherSuite, String protocol) {
+- Map<String, String> p2j = o2j.get(openSslCipherSuite);
+- if (p2j == null) {
+- p2j = cacheFromOpenSsl(openSslCipherSuite);
+- // This may happen if this method is queried when OpenSSL doesn't yet have a cipher setup. It will return
+- // "(NONE)" in this case.
+- if (p2j == null) {
+- return null;
+- }
+- }
+-
+- String javaCipherSuite = p2j.get(protocol);
+- if (javaCipherSuite == null) {
+- String cipher = p2j.get("");
+- if (cipher == null) {
+- return null;
+- }
+- javaCipherSuite = protocol + '_' + cipher;
- }
+-
+- return javaCipherSuite;
- }
-
-- /**
-- * Returns the cause of unavailability of
-- * <a href="http://netty.io/wiki/forked-tomcat-native.html">{@code netty-tcnative}</a> and its OpenSSL support.
-- *
-- * @return the cause if unavailable. {@code null} if available.
-- */
-- public static Throwable unavailabilityCause() {
-- return UNAVAILABILITY_CAUSE;
-- }
--
-- /**
-- * @deprecated use {@link #availableOpenSslCipherSuites()}
-- */
-- @Deprecated
-- public static Set<String> availableCipherSuites() {
-- return availableOpenSslCipherSuites();
-- }
+- private static Map<String, String> cacheFromOpenSsl(String openSslCipherSuite) {
+- Map<String, String> converted = o2jTls13.get(openSslCipherSuite);
+- if (converted != null) {
+- return converted;
+- }
-
-- /**
-- * Returns all the available OpenSSL cipher suites.
-- * Please note that the returned array may include the cipher suites that are insecure or non-functional.
-- */
-- public static Set<String> availableOpenSslCipherSuites() {
-- return AVAILABLE_OPENSSL_CIPHER_SUITES;
-- }
+- String javaCipherSuiteSuffix = toJavaUncached0(openSslCipherSuite, false);
+- if (javaCipherSuiteSuffix == null) {
+- return null;
+- }
-
-- /**
-- * Returns all the available cipher suites (Java-style).
-- * Please note that the returned array may include the cipher suites that are insecure or non-functional.
-- */
-- public static Set<String> availableJavaCipherSuites() {
-- return AVAILABLE_JAVA_CIPHER_SUITES;
-- }
+- final String javaCipherSuiteSsl = "SSL_" + javaCipherSuiteSuffix;
+- final String javaCipherSuiteTls = "TLS_" + javaCipherSuiteSuffix;
-
-- /**
-- * Returns {@code true} if and only if the specified cipher suite is available in OpenSSL.
-- * Both Java-style cipher suite and OpenSSL-style cipher suite are accepted.
-- */
-- public static boolean isCipherSuiteAvailable(String cipherSuite) {
-- String converted = CipherSuiteConverter.toOpenSsl(cipherSuite);
-- if (converted != null) {
-- cipherSuite = converted;
-- }
-- return AVAILABLE_OPENSSL_CIPHER_SUITES.contains(cipherSuite);
-- }
+- // Cache the mapping.
+- final Map<String, String> p2j = new HashMap<String, String>(4);
+- p2j.put("", javaCipherSuiteSuffix);
+- p2j.put("SSL", javaCipherSuiteSsl);
+- p2j.put("TLS", javaCipherSuiteTls);
+- o2j.putIfAbsent(openSslCipherSuite, p2j);
-
-- /**
-- * Returns {@code true} if {@link javax.net.ssl.KeyManagerFactory} is supported when using OpenSSL.
-- */
-- public static boolean supportsKeyManagerFactory() {
-- return SUPPORTS_KEYMANAGER_FACTORY;
-- }
+- // Cache the reverse mapping after adding the protocol prefix (TLS_ or SSL_)
+- j2o.putIfAbsent(javaCipherSuiteTls, openSslCipherSuite);
+- j2o.putIfAbsent(javaCipherSuiteSsl, openSslCipherSuite);
-
-- /**
-- * Returns {@code true} if <a href="https://wiki.openssl.org/index.php/Hostname_validation">Hostname Validation</a>
-- * is supported when using OpenSSL.
-- */
-- public static boolean supportsHostnameValidation() {
-- return SUPPORTS_HOSTNAME_VALIDATION;
-- }
+- logger.debug("Cipher suite mapping: {} => {}", javaCipherSuiteTls, openSslCipherSuite);
+- logger.debug("Cipher suite mapping: {} => {}", javaCipherSuiteSsl, openSslCipherSuite);
-
-- static boolean useKeyManagerFactory() {
-- return USE_KEYMANAGER_FACTORY;
+- return p2j;
- }
-
-- static long memoryAddress(ByteBuf buf) {
-- assert buf.isDirect();
-- return buf.hasMemoryAddress() ? buf.memoryAddress() : Buffer.address(buf.nioBuffer());
+- static String toJavaUncached(String openSslCipherSuite) {
+- return toJavaUncached0(openSslCipherSuite, true);
- }
-
-- private OpenSsl() { }
+- private static String toJavaUncached0(String openSslCipherSuite, boolean checkTls13) {
+- if (checkTls13) {
+- Map<String, String> converted = o2jTls13.get(openSslCipherSuite);
+- if (converted != null) {
+- return converted.get("TLS");
+- }
+- }
-
-- private static void loadTcNative() throws Exception {
-- String os = normalizeOs(SystemPropertyUtil.get("os.name", ""));
-- String arch = normalizeArch(SystemPropertyUtil.get("os.arch", ""));
+- Matcher m = OPENSSL_CIPHERSUITE_PATTERN.matcher(openSslCipherSuite);
+- if (!m.matches()) {
+- return null;
+- }
-
-- Set<String> libNames = new LinkedHashSet<String>(4);
-- // First, try loading the platform-specific library. Platform-specific
-- // libraries will be available if using a tcnative uber jar.
-- libNames.add("netty-tcnative-" + os + '-' + arch);
-- if (LINUX.equalsIgnoreCase(os)) {
-- // Fedora SSL lib so naming (libssl.so.10 vs libssl.so.1.0.0)..
-- libNames.add("netty-tcnative-" + os + '-' + arch + "-fedora");
+- String handshakeAlgo = m.group(1);
+- final boolean export;
+- if (handshakeAlgo == null) {
+- handshakeAlgo = "";
+- export = false;
+- } else if (handshakeAlgo.startsWith("EXP-")) {
+- handshakeAlgo = handshakeAlgo.substring(4);
+- export = true;
+- } else if ("EXP".equals(handshakeAlgo)) {
+- handshakeAlgo = "";
+- export = true;
+- } else {
+- export = false;
- }
-- // finally the default library.
-- libNames.add("netty-tcnative");
-- // in Java 8, statically compiled JNI code is namespaced
-- libNames.add("netty_tcnative");
-
-- NativeLibraryLoader.loadFirstAvailable(SSL.class.getClassLoader(),
-- libNames.toArray(new String[libNames.size()]));
-- }
+- handshakeAlgo = toJavaHandshakeAlgo(handshakeAlgo, export);
+- String bulkCipher = toJavaBulkCipher(m.group(2), export);
+- String hmacAlgo = toJavaHmacAlgo(m.group(3));
-
-- private static boolean initializeTcNative() throws Exception {
-- return Library.initialize();
+- String javaCipherSuite = handshakeAlgo + "_WITH_" + bulkCipher + '_' + hmacAlgo;
+- // For historical reasons the CHACHA20 ciphers do not follow OpenSSL's custom naming convention and omits the
+- // HMAC algorithm portion of the name. There is currently no way to derive this information because it is
+- // omitted from the OpenSSL cipher name, but they currently all use SHA256 for HMAC [1].
+- // [1] https://www.openssl.org/docs/man1.1.0/apps/ciphers.html
+- return bulkCipher.contains("CHACHA20") ? javaCipherSuite + "_SHA256" : javaCipherSuite;
- }
-
-- private static String normalizeOs(String value) {
-- value = normalize(value);
-- if (value.startsWith("aix")) {
-- return "aix";
+- private static String toJavaHandshakeAlgo(String handshakeAlgo, boolean export) {
+- if (handshakeAlgo.isEmpty()) {
+- handshakeAlgo = "RSA";
+- } else if ("ADH".equals(handshakeAlgo)) {
+- handshakeAlgo = "DH_anon";
+- } else if ("AECDH".equals(handshakeAlgo)) {
+- handshakeAlgo = "ECDH_anon";
- }
-- if (value.startsWith("hpux")) {
-- return "hpux";
+-
+- handshakeAlgo = handshakeAlgo.replace('-', '_');
+- if (export) {
+- return handshakeAlgo + "_EXPORT";
+- } else {
+- return handshakeAlgo;
- }
-- if (value.startsWith("os400")) {
-- // Avoid the names such as os4000
-- if (value.length() <= 5 || !Character.isDigit(value.charAt(5))) {
-- return "os400";
+- }
+-
+- private static String toJavaBulkCipher(String bulkCipher, boolean export) {
+- if (bulkCipher.startsWith("AES")) {
+- Matcher m = OPENSSL_AES_CBC_PATTERN.matcher(bulkCipher);
+- if (m.matches()) {
+- return m.replaceFirst("$1_$2_CBC");
+- }
+-
+- m = OPENSSL_AES_PATTERN.matcher(bulkCipher);
+- if (m.matches()) {
+- return m.replaceFirst("$1_$2_$3");
- }
- }
-- if (value.startsWith(LINUX)) {
-- return LINUX;
-- }
-- if (value.startsWith("macosx") || value.startsWith("osx")) {
-- return "osx";
-- }
-- if (value.startsWith("freebsd")) {
-- return "freebsd";
-- }
-- if (value.startsWith("openbsd")) {
-- return "openbsd";
+-
+- if ("DES-CBC3".equals(bulkCipher)) {
+- return "3DES_EDE_CBC";
- }
-- if (value.startsWith("netbsd")) {
-- return "netbsd";
+-
+- if ("RC4".equals(bulkCipher)) {
+- if (export) {
+- return "RC4_40";
+- } else {
+- return "RC4_128";
+- }
- }
-- if (value.startsWith("solaris") || value.startsWith("sunos")) {
-- return "sunos";
+-
+- if ("DES-CBC".equals(bulkCipher)) {
+- if (export) {
+- return "DES_CBC_40";
+- } else {
+- return "DES_CBC";
+- }
- }
-- if (value.startsWith("windows")) {
-- return "windows";
+-
+- if ("RC2-CBC".equals(bulkCipher)) {
+- if (export) {
+- return "RC2_CBC_40";
+- } else {
+- return "RC2_CBC";
+- }
- }
-
-- return UNKNOWN;
+- return bulkCipher.replace('-', '_');
- }
-
-- private static String normalizeArch(String value) {
-- value = normalize(value);
-- if (value.matches("^(x8664|amd64|ia32e|em64t|x64)$")) {
-- return "x86_64";
-- }
-- if (value.matches("^(x8632|x86|i[3-6]86|ia32|x32)$")) {
-- return "x86_32";
-- }
-- if (value.matches("^(ia64|itanium64)$")) {
-- return "itanium_64";
-- }
-- if (value.matches("^(sparc|sparc32)$")) {
-- return "sparc_32";
-- }
-- if (value.matches("^(sparcv9|sparc64)$")) {
-- return "sparc_64";
-- }
-- if (value.matches("^(arm|arm32)$")) {
-- return "arm_32";
-- }
-- if ("aarch64".equals(value)) {
-- return "aarch_64";
-- }
-- if (value.matches("^(ppc|ppc32)$")) {
-- return "ppc_32";
-- }
-- if ("ppc64".equals(value)) {
-- return "ppc_64";
+- private static String toJavaHmacAlgo(String hmacAlgo) {
+- // Java and OpenSSL use the same algorithm names for:
+- //
+- // * SHA
+- // * SHA256
+- // * MD5
+- //
+- return hmacAlgo;
+- }
+-
+- /**
+- * Convert the given ciphers if needed to OpenSSL format and append them to the correct {@link StringBuilder}
+- * depending on if its a TLSv1.3 cipher or not. If this methods returns without throwing an exception its
+- * guaranteed that at least one of the {@link StringBuilder}s contain some ciphers that can be used to configure
+- * OpenSSL.
+- */
+- static void convertToCipherStrings(Iterable<String> cipherSuites, StringBuilder cipherBuilder,
+- StringBuilder cipherTLSv13Builder, boolean boringSSL) {
+- for (String c: cipherSuites) {
+- if (c == null) {
+- break;
+- }
+-
+- String converted = toOpenSsl(c, boringSSL);
+- if (converted == null) {
+- converted = c;
+- }
+-
+- if (!OpenSsl.isCipherSuiteAvailable(converted)) {
+- throw new IllegalArgumentException("unsupported cipher suite: " + c + '(' + converted + ')');
+- }
+-
+- if (SslUtils.isTLSv13Cipher(converted) || SslUtils.isTLSv13Cipher(c)) {
+- cipherTLSv13Builder.append(converted);
+- cipherTLSv13Builder.append(':');
+- } else {
+- cipherBuilder.append(converted);
+- cipherBuilder.append(':');
+- }
- }
-- if ("ppc64le".equals(value)) {
-- return "ppcle_64";
+-
+- if (cipherBuilder.length() == 0 && cipherTLSv13Builder.length() == 0) {
+- throw new IllegalArgumentException("empty cipher suites");
- }
-- if ("s390".equals(value)) {
-- return "s390_32";
+- if (cipherBuilder.length() > 0) {
+- cipherBuilder.setLength(cipherBuilder.length() - 1);
- }
-- if ("s390x".equals(value)) {
-- return "s390_64";
+- if (cipherTLSv13Builder.length() > 0) {
+- cipherTLSv13Builder.setLength(cipherTLSv13Builder.length() - 1);
- }
--
-- return UNKNOWN;
- }
-
-- private static String normalize(String value) {
-- return value.toLowerCase(Locale.US).replaceAll("[^a-z0-9]+", "");
-- }
--
-- static void releaseIfNeeded(ReferenceCounted counted) {
-- if (counted.refCnt() > 0) {
-- ReferenceCountUtil.safeRelease(counted);
-- }
-- }
+- private CipherSuiteConverter() { }
-}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslCertificateException.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslCertificateException.java
+diff --git a/handler/src/main/java/io/netty/handler/ssl/DefaultOpenSslKeyMaterial.java b/handler/src/main/java/io/netty/handler/ssl/DefaultOpenSslKeyMaterial.java
deleted file mode 100644
-index 4672d00..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/OpenSslCertificateException.java
+index fcea5266f2..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/DefaultOpenSslKeyMaterial.java
+++ /dev/null
-@@ -1,79 +0,0 @@
+@@ -1,126 +0,0 @@
-/*
-- * Copyright 2016 The Netty Project
+- * Copyright 2018 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
@@ -629,74 +606,121 @@ index 4672d00..0000000
- */
-package io.netty.handler.ssl;
-
--import io.netty.internal.tcnative.CertificateVerifier;
+-import io.netty.internal.tcnative.SSL;
+-import io.netty.util.AbstractReferenceCounted;
+-import io.netty.util.IllegalReferenceCountException;
+-import io.netty.util.ResourceLeakDetector;
+-import io.netty.util.ResourceLeakDetectorFactory;
+-import io.netty.util.ResourceLeakTracker;
-
--import java.security.cert.CertificateException;
+-import java.security.cert.X509Certificate;
-
--/**
-- * A special {@link CertificateException} which allows to specify which error code is included in the
-- * SSL Record. This only work when {@link SslProvider#OPENSSL} or {@link SslProvider#OPENSSL_REFCNT} is used.
-- */
--public final class OpenSslCertificateException extends CertificateException {
-- private static final long serialVersionUID = 5542675253797129798L;
+-final class DefaultOpenSslKeyMaterial extends AbstractReferenceCounted implements OpenSslKeyMaterial {
-
-- private final int errorCode;
+- private static final ResourceLeakDetector<DefaultOpenSslKeyMaterial> leakDetector =
+- ResourceLeakDetectorFactory.instance().newResourceLeakDetector(DefaultOpenSslKeyMaterial.class);
+- private final ResourceLeakTracker<DefaultOpenSslKeyMaterial> leak;
+- private final X509Certificate[] x509CertificateChain;
+- private long chain;
+- private long privateKey;
-
-- /**
-- * Construct a new exception with the
-- * <a href="https://www.openssl.org/docs/manmaster/apps/verify.html">error code</a>.
-- */
-- public OpenSslCertificateException(int errorCode) {
-- this((String) null, errorCode);
+- DefaultOpenSslKeyMaterial(long chain, long privateKey, X509Certificate[] x509CertificateChain) {
+- this.chain = chain;
+- this.privateKey = privateKey;
+- this.x509CertificateChain = x509CertificateChain;
+- leak = leakDetector.track(this);
- }
-
-- /**
-- * Construct a new exception with the msg and
-- * <a href="https://www.openssl.org/docs/manmaster/apps/verify.html">error code</a> .
-- */
-- public OpenSslCertificateException(String msg, int errorCode) {
-- super(msg);
-- this.errorCode = checkErrorCode(errorCode);
+- @Override
+- public X509Certificate[] certificateChain() {
+- return x509CertificateChain.clone();
- }
-
-- /**
-- * Construct a new exception with the msg, cause and
-- * <a href="https://www.openssl.org/docs/manmaster/apps/verify.html">error code</a> .
-- */
-- public OpenSslCertificateException(String message, Throwable cause, int errorCode) {
-- super(message, cause);
-- this.errorCode = checkErrorCode(errorCode);
+- @Override
+- public long certificateChainAddress() {
+- if (refCnt() <= 0) {
+- throw new IllegalReferenceCountException();
+- }
+- return chain;
- }
-
-- /**
-- * Construct a new exception with the cause and
-- * <a href="https://www.openssl.org/docs/manmaster/apps/verify.html">error code</a> .
-- */
-- public OpenSslCertificateException(Throwable cause, int errorCode) {
-- this(null, cause, errorCode);
+- @Override
+- public long privateKeyAddress() {
+- if (refCnt() <= 0) {
+- throw new IllegalReferenceCountException();
+- }
+- return privateKey;
- }
-
-- /**
-- * Return the <a href="https://www.openssl.org/docs/man1.0.2/apps/verify.html">error code</a> to use.
-- */
-- public int errorCode() {
-- return errorCode;
+- @Override
+- protected void deallocate() {
+- SSL.freeX509Chain(chain);
+- chain = 0;
+- SSL.freePrivateKey(privateKey);
+- privateKey = 0;
+- if (leak != null) {
+- boolean closed = leak.close(this);
+- assert closed;
+- }
- }
-
-- private static int checkErrorCode(int errorCode) {
-- if (!CertificateVerifier.isValid(errorCode)) {
-- throw new IllegalArgumentException("errorCode '" + errorCode +
-- "' invalid, see https://www.openssl.org/docs/man1.0.2/apps/verify.html.");
+- @Override
+- public DefaultOpenSslKeyMaterial retain() {
+- if (leak != null) {
+- leak.record();
- }
-- return errorCode;
+- super.retain();
+- return this;
+- }
+-
+- @Override
+- public DefaultOpenSslKeyMaterial retain(int increment) {
+- if (leak != null) {
+- leak.record();
+- }
+- super.retain(increment);
+- return this;
+- }
+-
+- @Override
+- public DefaultOpenSslKeyMaterial touch() {
+- if (leak != null) {
+- leak.record();
+- }
+- super.touch();
+- return this;
+- }
+-
+- @Override
+- public DefaultOpenSslKeyMaterial touch(Object hint) {
+- if (leak != null) {
+- leak.record(hint);
+- }
+- return this;
+- }
+-
+- @Override
+- public boolean release() {
+- if (leak != null) {
+- leak.record();
+- }
+- return super.release();
+- }
+-
+- @Override
+- public boolean release(int decrement) {
+- if (leak != null) {
+- leak.record();
+- }
+- return super.release(decrement);
- }
-}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslClientContext.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslClientContext.java
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSsl.java b/handler/src/main/java/io/netty/handler/ssl/OpenSsl.java
deleted file mode 100644
-index 46412e9..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/OpenSslClientContext.java
+index d7d44cf3e7..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSsl.java
+++ /dev/null
-@@ -1,211 +0,0 @@
+@@ -1,610 +0,0 @@
-/*
- * Copyright 2014 The Netty Project
- *
@@ -712,210 +736,609 @@ index 46412e9..0000000
- * License for the specific language governing permissions and limitations
- * under the License.
- */
+-
-package io.netty.handler.ssl;
-
+-import io.netty.buffer.ByteBuf;
+-import io.netty.buffer.ByteBufAllocator;
+-import io.netty.buffer.UnpooledByteBufAllocator;
+-import io.netty.internal.tcnative.Buffer;
+-import io.netty.internal.tcnative.Library;
-import io.netty.internal.tcnative.SSL;
+-import io.netty.internal.tcnative.SSLContext;
+-import io.netty.util.CharsetUtil;
+-import io.netty.util.ReferenceCountUtil;
+-import io.netty.util.ReferenceCounted;
+-import io.netty.util.internal.EmptyArrays;
+-import io.netty.util.internal.NativeLibraryLoader;
+-import io.netty.util.internal.PlatformDependent;
+-import io.netty.util.internal.SystemPropertyUtil;
+-import io.netty.util.internal.logging.InternalLogger;
+-import io.netty.util.internal.logging.InternalLoggerFactory;
-
--import java.io.File;
--import java.security.PrivateKey;
+-import java.io.ByteArrayInputStream;
+-import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
+-import java.util.ArrayList;
+-import java.util.Collections;
+-import java.util.LinkedHashSet;
+-import java.util.List;
+-import java.util.Set;
-
--import javax.net.ssl.KeyManagerFactory;
--import javax.net.ssl.SSLException;
--import javax.net.ssl.TrustManager;
--import javax.net.ssl.TrustManagerFactory;
--
--import static io.netty.handler.ssl.ReferenceCountedOpenSslClientContext.newSessionContext;
+-import static io.netty.handler.ssl.SslUtils.*;
-
-/**
-- * A client-side {@link SslContext} which uses OpenSSL's SSL/TLS implementation.
-- * <p>This class will use a finalizer to ensure native resources are automatically cleaned up. To avoid finalizers
-- * and manually release the native memory see {@link ReferenceCountedOpenSslClientContext}.
+- * Tells if <a href="https://netty.io/wiki/forked-tomcat-native.html">{@code netty-tcnative}</a> and its OpenSSL support
+- * are available.
- */
--public final class OpenSslClientContext extends OpenSslContext {
-- private final OpenSslSessionContext sessionContext;
+-public final class OpenSsl {
-
-- /**
-- * Creates a new instance.
-- * @deprecated use {@link SslContextBuilder}
-- */
-- @Deprecated
-- public OpenSslClientContext() throws SSLException {
-- this((File) null, null, null, null, null, null, null, IdentityCipherSuiteFilter.INSTANCE, null, 0, 0);
+- private static final InternalLogger logger = InternalLoggerFactory.getInstance(OpenSsl.class);
+- private static final Throwable UNAVAILABILITY_CAUSE;
+-
+- static final List<String> DEFAULT_CIPHERS;
+- static final Set<String> AVAILABLE_CIPHER_SUITES;
+- private static final Set<String> AVAILABLE_OPENSSL_CIPHER_SUITES;
+- private static final Set<String> AVAILABLE_JAVA_CIPHER_SUITES;
+- private static final boolean SUPPORTS_KEYMANAGER_FACTORY;
+- private static final boolean USE_KEYMANAGER_FACTORY;
+- private static final boolean SUPPORTS_OCSP;
+- private static final boolean TLSV13_SUPPORTED;
+- private static final boolean IS_BORINGSSL;
+- static final Set<String> SUPPORTED_PROTOCOLS_SET;
+- static final String[] EXTRA_SUPPORTED_TLS_1_3_CIPHERS;
+-
+- // self-signed certificate for netty.io and the matching private-key
+- private static final String CERT = "-----BEGIN CERTIFICATE-----\n" +
+- "MIICrjCCAZagAwIBAgIIdSvQPv1QAZQwDQYJKoZIhvcNAQELBQAwFjEUMBIGA1UEAxMLZXhhbXBs\n" +
+- "ZS5jb20wIBcNMTgwNDA2MjIwNjU5WhgPOTk5OTEyMzEyMzU5NTlaMBYxFDASBgNVBAMTC2V4YW1w\n" +
+- "bGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAggbWsmDQ6zNzRZ5AW8E3eoGl\n" +
+- "qWvOBDb5Fs1oBRrVQHuYmVAoaqwDzXYJ0LOwa293AgWEQ1jpcbZ2hpoYQzqEZBTLnFhMrhRFlH6K\n" +
+- "bJND8Y33kZ/iSVBBDuGbdSbJShlM+4WwQ9IAso4MZ4vW3S1iv5fGGpLgbtXRmBf/RU8omN0Gijlv\n" +
+- "WlLWHWijLN8xQtySFuBQ7ssW8RcKAary3pUm6UUQB+Co6lnfti0Tzag8PgjhAJq2Z3wbsGRnP2YS\n" +
+- "vYoaK6qzmHXRYlp/PxrjBAZAmkLJs4YTm/XFF+fkeYx4i9zqHbyone5yerRibsHaXZWLnUL+rFoe\n" +
+- "MdKvr0VS3sGmhQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQADQi441pKmXf9FvUV5EHU4v8nJT9Iq\n" +
+- "yqwsKwXnr7AsUlDGHBD7jGrjAXnG5rGxuNKBQ35wRxJATKrUtyaquFUL6H8O6aGQehiFTk6zmPbe\n" +
+- "12Gu44vqqTgIUxnv3JQJiox8S2hMxsSddpeCmSdvmalvD6WG4NthH6B9ZaBEiep1+0s0RUaBYn73\n" +
+- "I7CCUaAtbjfR6pcJjrFk5ei7uwdQZFSJtkP2z8r7zfeANJddAKFlkaMWn7u+OIVuB4XPooWicObk\n" +
+- "NAHFtP65bocUYnDpTVdiyvn8DdqyZ/EO8n1bBKBzuSLplk2msW4pdgaFgY7Vw/0wzcFXfUXmL1uy\n" +
+- "G8sQD/wx\n" +
+- "-----END CERTIFICATE-----";
+-
+- private static final String KEY = "-----BEGIN PRIVATE KEY-----\n" +
+- "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCCBtayYNDrM3NFnkBbwTd6gaWp\n" +
+- "a84ENvkWzWgFGtVAe5iZUChqrAPNdgnQs7Brb3cCBYRDWOlxtnaGmhhDOoRkFMucWEyuFEWUfops\n" +
+- "k0PxjfeRn+JJUEEO4Zt1JslKGUz7hbBD0gCyjgxni9bdLWK/l8YakuBu1dGYF/9FTyiY3QaKOW9a\n" +
+- "UtYdaKMs3zFC3JIW4FDuyxbxFwoBqvLelSbpRRAH4KjqWd+2LRPNqDw+COEAmrZnfBuwZGc/ZhK9\n" +
+- "ihorqrOYddFiWn8/GuMEBkCaQsmzhhOb9cUX5+R5jHiL3OodvKid7nJ6tGJuwdpdlYudQv6sWh4x\n" +
+- "0q+vRVLewaaFAgMBAAECggEAP8tPJvFtTxhNJAkCloHz0D0vpDHqQBMgntlkgayqmBqLwhyb18pR\n" +
+- "i0qwgh7HHc7wWqOOQuSqlEnrWRrdcI6TSe8R/sErzfTQNoznKWIPYcI/hskk4sdnQ//Yn9/Jvnsv\n" +
+- "U/BBjOTJxtD+sQbhAl80JcA3R+5sArURQkfzzHOL/YMqzAsn5hTzp7HZCxUqBk3KaHRxV7NefeOE\n" +
+- "xlZuWSmxYWfbFIs4kx19/1t7h8CHQWezw+G60G2VBtSBBxDnhBWvqG6R/wpzJ3nEhPLLY9T+XIHe\n" +
+- "ipzdMOOOUZorfIg7M+pyYPji+ZIZxIpY5OjrOzXHciAjRtr5Y7l99K1CG1LguQKBgQDrQfIMxxtZ\n" +
+- "vxU/1cRmUV9l7pt5bjV5R6byXq178LxPKVYNjdZ840Q0/OpZEVqaT1xKVi35ohP1QfNjxPLlHD+K\n" +
+- "iDAR9z6zkwjIrbwPCnb5kuXy4lpwPcmmmkva25fI7qlpHtbcuQdoBdCfr/KkKaUCMPyY89LCXgEw\n" +
+- "5KTDj64UywKBgQCNfbO+eZLGzhiHhtNJurresCsIGWlInv322gL8CSfBMYl6eNfUTZvUDdFhPISL\n" +
+- "UljKWzXDrjw0ujFSPR0XhUGtiq89H+HUTuPPYv25gVXO+HTgBFZEPl4PpA+BUsSVZy0NddneyqLk\n" +
+- "42Wey9omY9Q8WsdNQS5cbUvy0uG6WFoX7wKBgQDZ1jpW8pa0x2bZsQsm4vo+3G5CRnZlUp+XlWt2\n" +
+- "dDcp5dC0xD1zbs1dc0NcLeGDOTDv9FSl7hok42iHXXq8AygjEm/QcuwwQ1nC2HxmQP5holAiUs4D\n" +
+- "WHM8PWs3wFYPzE459EBoKTxeaeP/uWAn+he8q7d5uWvSZlEcANs/6e77eQKBgD21Ar0hfFfj7mK8\n" +
+- "9E0FeRZBsqK3omkfnhcYgZC11Xa2SgT1yvs2Va2n0RcdM5kncr3eBZav2GYOhhAdwyBM55XuE/sO\n" +
+- "eokDVutNeuZ6d5fqV96TRaRBpvgfTvvRwxZ9hvKF4Vz+9wfn/JvCwANaKmegF6ejs7pvmF3whq2k\n" +
+- "drZVAoGAX5YxQ5XMTD0QbMAl7/6qp6S58xNoVdfCkmkj1ZLKaHKIjS/benkKGlySVQVPexPfnkZx\n" +
+- "p/Vv9yyphBoudiTBS9Uog66ueLYZqpgxlM/6OhYg86Gm3U2ycvMxYjBM1NFiyze21AqAhI+HX+Ot\n" +
+- "mraV2/guSgDgZAhukRZzeQ2RucI=\n" +
+- "-----END PRIVATE KEY-----";
+-
+- static {
+- Throwable cause = null;
+-
+- if (SystemPropertyUtil.getBoolean("io.netty.handler.ssl.noOpenSsl", false)) {
+- cause = new UnsupportedOperationException(
+- "OpenSSL was explicit disabled with -Dio.netty.handler.ssl.noOpenSsl=true");
+-
+- logger.debug(
+- "netty-tcnative explicit disabled; " +
+- OpenSslEngine.class.getSimpleName() + " will be unavailable.", cause);
+- } else {
+- // Test if netty-tcnative is in the classpath first.
+- try {
+- Class.forName("io.netty.internal.tcnative.SSLContext", false, OpenSsl.class.getClassLoader());
+- } catch (ClassNotFoundException t) {
+- cause = t;
+- logger.debug(
+- "netty-tcnative not in the classpath; " +
+- OpenSslEngine.class.getSimpleName() + " will be unavailable.");
+- }
+-
+- // If in the classpath, try to load the native library and initialize netty-tcnative.
+- if (cause == null) {
+- try {
+- // The JNI library was not already loaded. Load it now.
+- loadTcNative();
+- } catch (Throwable t) {
+- cause = t;
+- logger.debug(
+- "Failed to load netty-tcnative; " +
+- OpenSslEngine.class.getSimpleName() + " will be unavailable, unless the " +
+- "application has already loaded the symbols by some other means. " +
+- "See https://netty.io/wiki/forked-tomcat-native.html for more information.", t);
+- }
+-
+- try {
+- String engine = SystemPropertyUtil.get("io.netty.handler.ssl.openssl.engine", null);
+- if (engine == null) {
+- logger.debug("Initialize netty-tcnative using engine: 'default'");
+- } else {
+- logger.debug("Initialize netty-tcnative using engine: '{}'", engine);
+- }
+- initializeTcNative(engine);
+-
+- // The library was initialized successfully. If loading the library failed above,
+- // reset the cause now since it appears that the library was loaded by some other
+- // means.
+- cause = null;
+- } catch (Throwable t) {
+- if (cause == null) {
+- cause = t;
+- }
+- logger.debug(
+- "Failed to initialize netty-tcnative; " +
+- OpenSslEngine.class.getSimpleName() + " will be unavailable. " +
+- "See https://netty.io/wiki/forked-tomcat-native.html for more information.", t);
+- }
+- }
+- }
+-
+- UNAVAILABILITY_CAUSE = cause;
+-
+- if (cause == null) {
+- logger.debug("netty-tcnative using native library: {}", SSL.versionString());
+-
+- final List<String> defaultCiphers = new ArrayList<String>();
+- final Set<String> availableOpenSslCipherSuites = new LinkedHashSet<String>(128);
+- boolean supportsKeyManagerFactory = false;
+- boolean useKeyManagerFactory = false;
+- boolean tlsv13Supported = false;
+-
+- IS_BORINGSSL = "BoringSSL".equals(versionString());
+- if (IS_BORINGSSL) {
+- EXTRA_SUPPORTED_TLS_1_3_CIPHERS = new String [] { "TLS_AES_128_GCM_SHA256",
+- "TLS_AES_256_GCM_SHA384" ,
+- "TLS_CHACHA20_POLY1305_SHA256" };
+- } else {
+- EXTRA_SUPPORTED_TLS_1_3_CIPHERS = EmptyArrays.EMPTY_STRINGS;
+- }
+-
+- try {
+- final long sslCtx = SSLContext.make(SSL.SSL_PROTOCOL_ALL, SSL.SSL_MODE_SERVER);
+- long certBio = 0;
+- long keyBio = 0;
+- long cert = 0;
+- long key = 0;
+- try {
+- try {
+- StringBuilder tlsv13Ciphers = new StringBuilder();
+-
+- for (String cipher: TLSV13_CIPHERS) {
+- String converted = CipherSuiteConverter.toOpenSsl(cipher, IS_BORINGSSL);
+- if (converted != null) {
+- tlsv13Ciphers.append(converted).append(':');
+- }
+- }
+- if (tlsv13Ciphers.length() == 0) {
+- tlsv13Supported = false;
+- } else {
+- tlsv13Ciphers.setLength(tlsv13Ciphers.length() - 1);
+- SSLContext.setCipherSuite(sslCtx, tlsv13Ciphers.toString() , true);
+- tlsv13Supported = true;
+- }
+-
+- } catch (Exception ignore) {
+- tlsv13Supported = false;
+- }
+-
+- SSLContext.setCipherSuite(sslCtx, "ALL", false);
+-
+- final long ssl = SSL.newSSL(sslCtx, true);
+- try {
+- for (String c: SSL.getCiphers(ssl)) {
+- // Filter out bad input.
+- if (c == null || c.isEmpty() || availableOpenSslCipherSuites.contains(c) ||
+- // Filter out TLSv1.3 ciphers if not supported.
+- !tlsv13Supported && isTLSv13Cipher(c)) {
+- continue;
+- }
+- availableOpenSslCipherSuites.add(c);
+- }
+- if (IS_BORINGSSL) {
+- // Currently BoringSSL does not include these when calling SSL.getCiphers() even when these
+- // are supported.
+- Collections.addAll(availableOpenSslCipherSuites, EXTRA_SUPPORTED_TLS_1_3_CIPHERS);
+- Collections.addAll(availableOpenSslCipherSuites,
+- "AEAD-AES128-GCM-SHA256",
+- "AEAD-AES256-GCM-SHA384",
+- "AEAD-CHACHA20-POLY1305-SHA256");
+- }
+-
+- PemEncoded privateKey = PemPrivateKey.valueOf(KEY.getBytes(CharsetUtil.US_ASCII));
+- try {
+- // Let's check if we can set a callback, which may not work if the used OpenSSL version
+- // is to old.
+- SSLContext.setCertificateCallback(sslCtx, null);
+-
+- X509Certificate certificate = selfSignedCertificate();
+- certBio = ReferenceCountedOpenSslContext.toBIO(ByteBufAllocator.DEFAULT, certificate);
+- cert = SSL.parseX509Chain(certBio);
+-
+- keyBio = ReferenceCountedOpenSslContext.toBIO(
+- UnpooledByteBufAllocator.DEFAULT, privateKey.retain());
+- key = SSL.parsePrivateKey(keyBio, null);
+-
+- SSL.setKeyMaterial(ssl, cert, key);
+- supportsKeyManagerFactory = true;
+- try {
+- boolean propertySet = SystemPropertyUtil.contains(
+- "io.netty.handler.ssl.openssl.useKeyManagerFactory");
+- if (!IS_BORINGSSL) {
+- useKeyManagerFactory = SystemPropertyUtil.getBoolean(
+- "io.netty.handler.ssl.openssl.useKeyManagerFactory", true);
+-
+- if (propertySet) {
+- logger.info("System property " +
+- "'io.netty.handler.ssl.openssl.useKeyManagerFactory'" +
+- " is deprecated and so will be ignored in the future");
+- }
+- } else {
+- useKeyManagerFactory = true;
+- if (propertySet) {
+- logger.info("System property " +
+- "'io.netty.handler.ssl.openssl.useKeyManagerFactory'" +
+- " is deprecated and will be ignored when using BoringSSL");
+- }
+- }
+- } catch (Throwable ignore) {
+- logger.debug("Failed to get useKeyManagerFactory system property.");
+- }
+- } catch (Error ignore) {
+- logger.debug("KeyManagerFactory not supported.");
+- } finally {
+- privateKey.release();
+- }
+- } finally {
+- SSL.freeSSL(ssl);
+- if (certBio != 0) {
+- SSL.freeBIO(certBio);
+- }
+- if (keyBio != 0) {
+- SSL.freeBIO(keyBio);
+- }
+- if (cert != 0) {
+- SSL.freeX509Chain(cert);
+- }
+- if (key != 0) {
+- SSL.freePrivateKey(key);
+- }
+- }
+- } finally {
+- SSLContext.free(sslCtx);
+- }
+- } catch (Exception e) {
+- logger.warn("Failed to get the list of available OpenSSL cipher suites.", e);
+- }
+- AVAILABLE_OPENSSL_CIPHER_SUITES = Collections.unmodifiableSet(availableOpenSslCipherSuites);
+- final Set<String> availableJavaCipherSuites = new LinkedHashSet<String>(
+- AVAILABLE_OPENSSL_CIPHER_SUITES.size() * 2);
+- for (String cipher: AVAILABLE_OPENSSL_CIPHER_SUITES) {
+- // Included converted but also openssl cipher name
+- if (!isTLSv13Cipher(cipher)) {
+- availableJavaCipherSuites.add(CipherSuiteConverter.toJava(cipher, "TLS"));
+- availableJavaCipherSuites.add(CipherSuiteConverter.toJava(cipher, "SSL"));
+- } else {
+- // TLSv1.3 ciphers have the correct format.
+- availableJavaCipherSuites.add(cipher);
+- }
+- }
+-
+- addIfSupported(availableJavaCipherSuites, defaultCiphers, DEFAULT_CIPHER_SUITES);
+- addIfSupported(availableJavaCipherSuites, defaultCiphers, TLSV13_CIPHER_SUITES);
+-
+- useFallbackCiphersIfDefaultIsEmpty(defaultCiphers, availableJavaCipherSuites);
+- DEFAULT_CIPHERS = Collections.unmodifiableList(defaultCiphers);
+-
+- AVAILABLE_JAVA_CIPHER_SUITES = Collections.unmodifiableSet(availableJavaCipherSuites);
+-
+- final Set<String> availableCipherSuites = new LinkedHashSet<String>(
+- AVAILABLE_OPENSSL_CIPHER_SUITES.size() + AVAILABLE_JAVA_CIPHER_SUITES.size());
+- availableCipherSuites.addAll(AVAILABLE_OPENSSL_CIPHER_SUITES);
+- availableCipherSuites.addAll(AVAILABLE_JAVA_CIPHER_SUITES);
+-
+- AVAILABLE_CIPHER_SUITES = availableCipherSuites;
+- SUPPORTS_KEYMANAGER_FACTORY = supportsKeyManagerFactory;
+- USE_KEYMANAGER_FACTORY = useKeyManagerFactory;
+-
+- Set<String> protocols = new LinkedHashSet<String>(6);
+- // Seems like there is no way to explicitly disable SSLv2Hello in openssl so it is always enabled
+- protocols.add(PROTOCOL_SSL_V2_HELLO);
+- if (doesSupportProtocol(SSL.SSL_PROTOCOL_SSLV2, SSL.SSL_OP_NO_SSLv2)) {
+- protocols.add(PROTOCOL_SSL_V2);
+- }
+- if (doesSupportProtocol(SSL.SSL_PROTOCOL_SSLV3, SSL.SSL_OP_NO_SSLv3)) {
+- protocols.add(PROTOCOL_SSL_V3);
+- }
+- if (doesSupportProtocol(SSL.SSL_PROTOCOL_TLSV1, SSL.SSL_OP_NO_TLSv1)) {
+- protocols.add(PROTOCOL_TLS_V1);
+- }
+- if (doesSupportProtocol(SSL.SSL_PROTOCOL_TLSV1_1, SSL.SSL_OP_NO_TLSv1_1)) {
+- protocols.add(PROTOCOL_TLS_V1_1);
+- }
+- if (doesSupportProtocol(SSL.SSL_PROTOCOL_TLSV1_2, SSL.SSL_OP_NO_TLSv1_2)) {
+- protocols.add(PROTOCOL_TLS_V1_2);
+- }
+-
+- // This is only supported by java11 and later.
+- if (tlsv13Supported && doesSupportProtocol(SSL.SSL_PROTOCOL_TLSV1_3, SSL.SSL_OP_NO_TLSv1_3)) {
+- protocols.add(PROTOCOL_TLS_V1_3);
+- TLSV13_SUPPORTED = true;
+- } else {
+- TLSV13_SUPPORTED = false;
+- }
+-
+- SUPPORTED_PROTOCOLS_SET = Collections.unmodifiableSet(protocols);
+- SUPPORTS_OCSP = doesSupportOcsp();
+-
+- if (logger.isDebugEnabled()) {
+- logger.debug("Supported protocols (OpenSSL): {} ", SUPPORTED_PROTOCOLS_SET);
+- logger.debug("Default cipher suites (OpenSSL): {}", DEFAULT_CIPHERS);
+- }
+- } else {
+- DEFAULT_CIPHERS = Collections.emptyList();
+- AVAILABLE_OPENSSL_CIPHER_SUITES = Collections.emptySet();
+- AVAILABLE_JAVA_CIPHER_SUITES = Collections.emptySet();
+- AVAILABLE_CIPHER_SUITES = Collections.emptySet();
+- SUPPORTS_KEYMANAGER_FACTORY = false;
+- USE_KEYMANAGER_FACTORY = false;
+- SUPPORTED_PROTOCOLS_SET = Collections.emptySet();
+- SUPPORTS_OCSP = false;
+- TLSV13_SUPPORTED = false;
+- IS_BORINGSSL = false;
+- EXTRA_SUPPORTED_TLS_1_3_CIPHERS = EmptyArrays.EMPTY_STRINGS;
+- }
- }
-
- /**
-- * Creates a new instance.
-- *
-- * @param certChainFile an X.509 certificate chain file in PEM format.
-- * {@code null} to use the system default
-- * @deprecated use {@link SslContextBuilder}
+- * Returns a self-signed {@link X509Certificate} for {@code netty.io}.
- */
-- @Deprecated
-- public OpenSslClientContext(File certChainFile) throws SSLException {
-- this(certChainFile, null);
+- static X509Certificate selfSignedCertificate() throws CertificateException {
+- return (X509Certificate) SslContext.X509_CERT_FACTORY.generateCertificate(
+- new ByteArrayInputStream(CERT.getBytes(CharsetUtil.US_ASCII))
+- );
+- }
+-
+- private static boolean doesSupportOcsp() {
+- boolean supportsOcsp = false;
+- if (version() >= 0x10002000L) {
+- long sslCtx = -1;
+- try {
+- sslCtx = SSLContext.make(SSL.SSL_PROTOCOL_TLSV1_2, SSL.SSL_MODE_SERVER);
+- SSLContext.enableOcsp(sslCtx, false);
+- supportsOcsp = true;
+- } catch (Exception ignore) {
+- // ignore
+- } finally {
+- if (sslCtx != -1) {
+- SSLContext.free(sslCtx);
+- }
+- }
+- }
+- return supportsOcsp;
+- }
+- private static boolean doesSupportProtocol(int protocol, int opt) {
+- if (opt == 0) {
+- // If the opt is 0 the protocol is not supported. This is for example the case with BoringSSL and SSLv2.
+- return false;
+- }
+- long sslCtx = -1;
+- try {
+- sslCtx = SSLContext.make(protocol, SSL.SSL_MODE_COMBINED);
+- return true;
+- } catch (Exception ignore) {
+- return false;
+- } finally {
+- if (sslCtx != -1) {
+- SSLContext.free(sslCtx);
+- }
+- }
- }
-
- /**
-- * Creates a new instance.
-- *
-- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
-- * that verifies the certificates sent from servers.
-- * {@code null} to use the default.
-- * @deprecated use {@link SslContextBuilder}
+- * Returns {@code true} if and only if
+- * <a href="https://netty.io/wiki/forked-tomcat-native.html">{@code netty-tcnative}</a> and its OpenSSL support
+- * are available.
- */
-- @Deprecated
-- public OpenSslClientContext(TrustManagerFactory trustManagerFactory) throws SSLException {
-- this(null, trustManagerFactory);
+- public static boolean isAvailable() {
+- return UNAVAILABILITY_CAUSE == null;
- }
-
- /**
-- * Creates a new instance.
+- * Returns {@code true} if the used version of openssl supports
+- * <a href="https://tools.ietf.org/html/rfc7301">ALPN</a>.
- *
-- * @param certChainFile an X.509 certificate chain file in PEM format.
-- * {@code null} to use the system default
-- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
-- * that verifies the certificates sent from servers.
-- * {@code null} to use the default.
-- * @deprecated use {@link SslContextBuilder}
+- * @deprecated use {@link SslProvider#isAlpnSupported(SslProvider)} with {@link SslProvider#OPENSSL}.
- */
- @Deprecated
-- public OpenSslClientContext(File certChainFile, TrustManagerFactory trustManagerFactory) throws SSLException {
-- this(certChainFile, trustManagerFactory, null, null, null, null, null,
-- IdentityCipherSuiteFilter.INSTANCE, null, 0, 0);
+- public static boolean isAlpnSupported() {
+- return version() >= 0x10002000L;
- }
-
- /**
-- * Creates a new instance.
-- *
-- * @param certChainFile an X.509 certificate chain file in PEM format
-- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
-- * that verifies the certificates sent from servers.
-- * {@code null} to use the default..
-- * @param ciphers the cipher suites to enable, in the order of preference.
-- * {@code null} to use the default cipher suites.
-- * @param apn Provides a means to configure parameters related to application protocol negotiation.
-- * @param sessionCacheSize the size of the cache used for storing SSL session objects.
-- * {@code 0} to use the default value.
-- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
-- * {@code 0} to use the default value.
-- * @deprecated use {@link SslContextBuilder}
+- * Returns {@code true} if the used version of OpenSSL supports OCSP stapling.
- */
-- @Deprecated
-- public OpenSslClientContext(File certChainFile, TrustManagerFactory trustManagerFactory, Iterable<String> ciphers,
-- ApplicationProtocolConfig apn, long sessionCacheSize, long sessionTimeout)
-- throws SSLException {
-- this(certChainFile, trustManagerFactory, null, null, null, null, ciphers, IdentityCipherSuiteFilter.INSTANCE,
-- apn, sessionCacheSize, sessionTimeout);
+- public static boolean isOcspSupported() {
+- return SUPPORTS_OCSP;
- }
-
- /**
-- * Creates a new instance.
-- *
-- * @param certChainFile an X.509 certificate chain file in PEM format
-- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
-- * that verifies the certificates sent from servers.
-- * {@code null} to use the default..
-- * @param ciphers the cipher suites to enable, in the order of preference.
-- * {@code null} to use the default cipher suites.
-- * @param cipherFilter a filter to apply over the supplied list of ciphers
-- * @param apn Provides a means to configure parameters related to application protocol negotiation.
-- * @param sessionCacheSize the size of the cache used for storing SSL session objects.
-- * {@code 0} to use the default value.
-- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
-- * {@code 0} to use the default value.
-- * @deprecated use {@link SslContextBuilder}
+- * Returns the version of the used available OpenSSL library or {@code -1} if {@link #isAvailable()}
+- * returns {@code false}.
+- */
+- public static int version() {
+- return isAvailable() ? SSL.version() : -1;
+- }
+-
+- /**
+- * Returns the version string of the used available OpenSSL library or {@code null} if {@link #isAvailable()}
+- * returns {@code false}.
+- */
+- public static String versionString() {
+- return isAvailable() ? SSL.versionString() : null;
+- }
+-
+- /**
+- * Ensure that <a href="https://netty.io/wiki/forked-tomcat-native.html">{@code netty-tcnative}</a> and
+- * its OpenSSL support are available.
+- *
+- * @throws UnsatisfiedLinkError if unavailable
+- */
+- public static void ensureAvailability() {
+- if (UNAVAILABILITY_CAUSE != null) {
+- throw (Error) new UnsatisfiedLinkError(
+- "failed to load the required native library").initCause(UNAVAILABILITY_CAUSE);
+- }
+- }
+-
+- /**
+- * Returns the cause of unavailability of
+- * <a href="https://netty.io/wiki/forked-tomcat-native.html">{@code netty-tcnative}</a> and its OpenSSL support.
+- *
+- * @return the cause if unavailable. {@code null} if available.
+- */
+- public static Throwable unavailabilityCause() {
+- return UNAVAILABILITY_CAUSE;
+- }
+-
+- /**
+- * @deprecated use {@link #availableOpenSslCipherSuites()}
- */
- @Deprecated
-- public OpenSslClientContext(File certChainFile, TrustManagerFactory trustManagerFactory, Iterable<String> ciphers,
-- CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
-- long sessionCacheSize, long sessionTimeout) throws SSLException {
-- this(certChainFile, trustManagerFactory, null, null, null, null,
-- ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout);
+- public static Set<String> availableCipherSuites() {
+- return availableOpenSslCipherSuites();
- }
-
- /**
-- * Creates a new instance.
-- * @param trustCertCollectionFile an X.509 certificate collection file in PEM format.
-- * {@code null} to use the system default
-- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
-- * that verifies the certificates sent from servers.
-- * {@code null} to use the default or the results of parsing
-- * {@code trustCertCollectionFile}
-- * @param keyCertChainFile an X.509 certificate chain file in PEM format.
-- * This provides the public key for mutual authentication.
-- * {@code null} to use the system default
-- * @param keyFile a PKCS#8 private key file in PEM format.
-- * This provides the private key for mutual authentication.
-- * {@code null} for no mutual authentication.
-- * @param keyPassword the password of the {@code keyFile}.
-- * {@code null} if it's not password-protected.
-- * Ignored if {@code keyFile} is {@code null}.
-- * @param keyManagerFactory the {@link KeyManagerFactory} that provides the {@link javax.net.ssl.KeyManager}s
-- * that is used to encrypt data being sent to servers.
-- * {@code null} to use the default or the results of parsing
-- * {@code keyCertChainFile} and {@code keyFile}.
-- * @param ciphers the cipher suites to enable, in the order of preference.
-- * {@code null} to use the default cipher suites.
-- * @param cipherFilter a filter to apply over the supplied list of ciphers
-- * @param apn Application Protocol Negotiator object.
-- * @param sessionCacheSize the size of the cache used for storing SSL session objects.
-- * {@code 0} to use the default value.
-- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
-- * {@code 0} to use the default value.
-- * @deprecated use {@link SslContextBuilder}
+- * Returns all the available OpenSSL cipher suites.
+- * Please note that the returned array may include the cipher suites that are insecure or non-functional.
+- */
+- public static Set<String> availableOpenSslCipherSuites() {
+- return AVAILABLE_OPENSSL_CIPHER_SUITES;
+- }
+-
+- /**
+- * Returns all the available cipher suites (Java-style).
+- * Please note that the returned array may include the cipher suites that are insecure or non-functional.
+- */
+- public static Set<String> availableJavaCipherSuites() {
+- return AVAILABLE_JAVA_CIPHER_SUITES;
+- }
+-
+- /**
+- * Returns {@code true} if and only if the specified cipher suite is available in OpenSSL.
+- * Both Java-style cipher suite and OpenSSL-style cipher suite are accepted.
+- */
+- public static boolean isCipherSuiteAvailable(String cipherSuite) {
+- String converted = CipherSuiteConverter.toOpenSsl(cipherSuite, IS_BORINGSSL);
+- if (converted != null) {
+- cipherSuite = converted;
+- }
+- return AVAILABLE_OPENSSL_CIPHER_SUITES.contains(cipherSuite);
+- }
+-
+- /**
+- * Returns {@code true} if {@link javax.net.ssl.KeyManagerFactory} is supported when using OpenSSL.
+- */
+- public static boolean supportsKeyManagerFactory() {
+- return SUPPORTS_KEYMANAGER_FACTORY;
+- }
+-
+- /**
+- * Always returns {@code true} if {@link #isAvailable()} returns {@code true}.
+- *
+- * @deprecated Will be removed because hostname validation is always done by a
+- * {@link javax.net.ssl.TrustManager} implementation.
- */
- @Deprecated
-- public OpenSslClientContext(File trustCertCollectionFile, TrustManagerFactory trustManagerFactory,
-- File keyCertChainFile, File keyFile, String keyPassword,
-- KeyManagerFactory keyManagerFactory, Iterable<String> ciphers,
-- CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
-- long sessionCacheSize, long sessionTimeout)
-- throws SSLException {
-- this(toX509CertificatesInternal(trustCertCollectionFile), trustManagerFactory,
-- toX509CertificatesInternal(keyCertChainFile), toPrivateKeyInternal(keyFile, keyPassword),
-- keyPassword, keyManagerFactory, ciphers, cipherFilter, apn, null, sessionCacheSize,
-- sessionTimeout, false);
+- public static boolean supportsHostnameValidation() {
+- return isAvailable();
- }
-
-- OpenSslClientContext(X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory,
-- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword,
-- KeyManagerFactory keyManagerFactory, Iterable<String> ciphers,
-- CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, String[] protocols,
-- long sessionCacheSize, long sessionTimeout, boolean enableOcsp)
-- throws SSLException {
-- super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, SSL.SSL_MODE_CLIENT, keyCertChain,
-- ClientAuth.NONE, protocols, false, enableOcsp);
-- boolean success = false;
-- try {
-- sessionContext = newSessionContext(this, ctx, engineMap, trustCertCollection, trustManagerFactory,
-- keyCertChain, key, keyPassword, keyManagerFactory);
-- success = true;
-- } finally {
-- if (!success) {
-- release();
-- }
+- static boolean useKeyManagerFactory() {
+- return USE_KEYMANAGER_FACTORY;
+- }
+-
+- static long memoryAddress(ByteBuf buf) {
+- assert buf.isDirect();
+- return buf.hasMemoryAddress() ? buf.memoryAddress() : Buffer.address(buf.nioBuffer());
+- }
+-
+- private OpenSsl() { }
+-
+- private static void loadTcNative() throws Exception {
+- String os = PlatformDependent.normalizedOs();
+- String arch = PlatformDependent.normalizedArch();
+-
+- Set<String> libNames = new LinkedHashSet<String>(5);
+- String staticLibName = "netty_tcnative";
+-
+- // First, try loading the platform-specific library. Platform-specific
+- // libraries will be available if using a tcnative uber jar.
+- if ("linux".equalsIgnoreCase(os)) {
+- Set<String> classifiers = PlatformDependent.normalizedLinuxClassifiers();
+- for (String classifier : classifiers) {
+- libNames.add(staticLibName + "_" + os + '_' + arch + "_" + classifier);
+- }
+- // generic arch-dependent library
+- libNames.add(staticLibName + "_" + os + '_' + arch);
+-
+- // Fedora SSL lib so naming (libssl.so.10 vs libssl.so.1.0.0).
+- // note: should already be included from the classifiers but if not, we use this as an
+- // additional fallback option here
+- libNames.add(staticLibName + "_" + os + '_' + arch + "_fedora");
+- } else {
+- libNames.add(staticLibName + "_" + os + '_' + arch);
- }
+- libNames.add(staticLibName + "_" + arch);
+- libNames.add(staticLibName);
+-
+- NativeLibraryLoader.loadFirstAvailable(SSLContext.class.getClassLoader(),
+- libNames.toArray(new String[0]));
- }
-
-- @Override
-- public OpenSslSessionContext sessionContext() {
-- return sessionContext;
+- private static boolean initializeTcNative(String engine) throws Exception {
+- return Library.initialize("provided", engine);
- }
-
-- @Override
-- OpenSslKeyMaterialManager keyMaterialManager() {
-- return null;
+- static void releaseIfNeeded(ReferenceCounted counted) {
+- if (counted.refCnt() > 0) {
+- ReferenceCountUtil.safeRelease(counted);
+- }
+- }
+-
+- static boolean isTlsv13Supported() {
+- return TLSV13_SUPPORTED;
+- }
+-
+- static boolean isBoringSSL() {
+- return IS_BORINGSSL;
- }
-}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslContext.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslContext.java
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslCachingKeyMaterialProvider.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslCachingKeyMaterialProvider.java
deleted file mode 100644
-index c4ca6b5..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/OpenSslContext.java
+index 07b67d9fa7..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslCachingKeyMaterialProvider.java
+++ /dev/null
-@@ -1,58 +0,0 @@
+@@ -1,79 +0,0 @@
-/*
-- * Copyright 2014 The Netty Project
+- * Copyright 2018 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
@@ -933,53 +1356,74 @@ index c4ca6b5..0000000
-
-import io.netty.buffer.ByteBufAllocator;
-
--import java.security.cert.Certificate;
--
--import javax.net.ssl.SSLEngine;
--import javax.net.ssl.SSLException;
+-import javax.net.ssl.X509KeyManager;
+-import java.util.Iterator;
+-import java.util.concurrent.ConcurrentHashMap;
+-import java.util.concurrent.ConcurrentMap;
-
-/**
-- * This class will use a finalizer to ensure native resources are automatically cleaned up. To avoid finalizers
-- * and manually release the native memory see {@link ReferenceCountedOpenSslContext}.
+- * {@link OpenSslKeyMaterialProvider} that will cache the {@link OpenSslKeyMaterial} to reduce the overhead
+- * of parsing the chain and the key for generation of the material.
- */
--public abstract class OpenSslContext extends ReferenceCountedOpenSslContext {
-- OpenSslContext(Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apnCfg,
-- long sessionCacheSize, long sessionTimeout, int mode, Certificate[] keyCertChain,
-- ClientAuth clientAuth, String[] protocols, boolean startTls, boolean enableOcsp)
-- throws SSLException {
-- super(ciphers, cipherFilter, apnCfg, sessionCacheSize, sessionTimeout, mode, keyCertChain,
-- clientAuth, protocols, startTls, enableOcsp, false);
-- }
+-final class OpenSslCachingKeyMaterialProvider extends OpenSslKeyMaterialProvider {
-
-- OpenSslContext(Iterable<String> ciphers, CipherSuiteFilter cipherFilter,
-- OpenSslApplicationProtocolNegotiator apn, long sessionCacheSize,
-- long sessionTimeout, int mode, Certificate[] keyCertChain,
-- ClientAuth clientAuth, String[] protocols, boolean startTls,
-- boolean enableOcsp) throws SSLException {
-- super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, mode, keyCertChain, clientAuth, protocols,
-- startTls, enableOcsp, false);
+- private final int maxCachedEntries;
+- private volatile boolean full;
+- private final ConcurrentMap<String, OpenSslKeyMaterial> cache = new ConcurrentHashMap<String, OpenSslKeyMaterial>();
+-
+- OpenSslCachingKeyMaterialProvider(X509KeyManager keyManager, String password, int maxCachedEntries) {
+- super(keyManager, password);
+- this.maxCachedEntries = maxCachedEntries;
- }
-
- @Override
-- final SSLEngine newEngine0(ByteBufAllocator alloc, String peerHost, int peerPort) {
-- return new OpenSslEngine(this, alloc, peerHost, peerPort);
+- OpenSslKeyMaterial chooseKeyMaterial(ByteBufAllocator allocator, String alias) throws Exception {
+- OpenSslKeyMaterial material = cache.get(alias);
+- if (material == null) {
+- material = super.chooseKeyMaterial(allocator, alias);
+- if (material == null) {
+- // No keymaterial should be used.
+- return null;
+- }
+-
+- if (full) {
+- return material;
+- }
+- if (cache.size() > maxCachedEntries) {
+- full = true;
+- // Do not cache...
+- return material;
+- }
+- OpenSslKeyMaterial old = cache.putIfAbsent(alias, material);
+- if (old != null) {
+- material.release();
+- material = old;
+- }
+- }
+- // We need to call retain() as we want to always have at least a refCnt() of 1 before destroy() was called.
+- return material.retain();
- }
-
- @Override
-- @SuppressWarnings("FinalizeDeclaration")
-- protected final void finalize() throws Throwable {
-- super.finalize();
-- OpenSsl.releaseIfNeeded(this);
+- void destroy() {
+- // Remove and release all entries.
+- do {
+- Iterator<OpenSslKeyMaterial> iterator = cache.values().iterator();
+- while (iterator.hasNext()) {
+- iterator.next().release();
+- iterator.remove();
+- }
+- } while (!cache.isEmpty());
- }
-}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslEngine.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslEngine.java
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslCachingX509KeyManagerFactory.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslCachingX509KeyManagerFactory.java
deleted file mode 100644
-index cbc7ee4..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/OpenSslEngine.java
+index 7f67bc8198..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslCachingX509KeyManagerFactory.java
+++ /dev/null
-@@ -1,40 +0,0 @@
+@@ -1,81 +0,0 @@
-/*
-- * Copyright 2014 The Netty Project
+- * Copyright 2018 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
@@ -995,37 +1439,78 @@ index cbc7ee4..0000000
- */
-package io.netty.handler.ssl;
-
--import io.netty.buffer.ByteBufAllocator;
+-import io.netty.util.internal.ObjectUtil;
-
--import javax.net.ssl.SSLEngine;
+-import javax.net.ssl.KeyManager;
+-import javax.net.ssl.KeyManagerFactory;
+-import javax.net.ssl.KeyManagerFactorySpi;
+-import javax.net.ssl.ManagerFactoryParameters;
+-import javax.net.ssl.X509ExtendedKeyManager;
+-import javax.net.ssl.X509KeyManager;
+-import java.security.InvalidAlgorithmParameterException;
+-import java.security.KeyStore;
+-import java.security.KeyStoreException;
+-import java.security.NoSuchAlgorithmException;
+-import java.security.PrivateKey;
+-import java.security.UnrecoverableKeyException;
+-import java.security.cert.X509Certificate;
-
-/**
-- * Implements a {@link SSLEngine} using
-- * <a href="https://www.openssl.org/docs/crypto/BIO_s_bio.html#EXAMPLE">OpenSSL BIO abstractions</a>.
-- * <p>
-- * This class will use a finalizer to ensure native resources are automatically cleaned up. To avoid finalizers
-- * and manually release the native memory see {@link ReferenceCountedOpenSslEngine}.
+- * Wraps another {@link KeyManagerFactory} and caches its chains / certs for an alias for better performance when using
+- * {@link SslProvider#OPENSSL} or {@link SslProvider#OPENSSL_REFCNT}.
+- *
+- * Because of the caching its important that the wrapped {@link KeyManagerFactory}s {@link X509KeyManager}s always
+- * return the same {@link X509Certificate} chain and {@link PrivateKey} for the same alias.
- */
--public final class OpenSslEngine extends ReferenceCountedOpenSslEngine {
-- OpenSslEngine(OpenSslContext context, ByteBufAllocator alloc, String peerHost, int peerPort) {
-- super(context, alloc, peerHost, peerPort, false);
+-public final class OpenSslCachingX509KeyManagerFactory extends KeyManagerFactory {
+-
+- private final int maxCachedEntries;
+-
+- public OpenSslCachingX509KeyManagerFactory(final KeyManagerFactory factory) {
+- this(factory, 1024);
- }
-
-- @Override
-- @SuppressWarnings("FinalizeDeclaration")
-- protected void finalize() throws Throwable {
-- super.finalize();
-- OpenSsl.releaseIfNeeded(this);
+- public OpenSslCachingX509KeyManagerFactory(final KeyManagerFactory factory, int maxCachedEntries) {
+- super(new KeyManagerFactorySpi() {
+- @Override
+- protected void engineInit(KeyStore keyStore, char[] chars)
+- throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
+- factory.init(keyStore, chars);
+- }
+-
+- @Override
+- protected void engineInit(ManagerFactoryParameters managerFactoryParameters)
+- throws InvalidAlgorithmParameterException {
+- factory.init(managerFactoryParameters);
+- }
+-
+- @Override
+- protected KeyManager[] engineGetKeyManagers() {
+- return factory.getKeyManagers();
+- }
+- }, factory.getProvider(), factory.getAlgorithm());
+- this.maxCachedEntries = ObjectUtil.checkPositive(maxCachedEntries, "maxCachedEntries");
+- }
+-
+- OpenSslKeyMaterialProvider newProvider(String password) {
+- X509KeyManager keyManager = ReferenceCountedOpenSslContext.chooseX509KeyManager(getKeyManagers());
+- if ("sun.security.ssl.X509KeyManagerImpl".equals(keyManager.getClass().getName())) {
+- // Don't do caching if X509KeyManagerImpl is used as the returned aliases are not stable and will change
+- // between invocations.
+- return new OpenSslKeyMaterialProvider(keyManager, password);
+- }
+- return new OpenSslCachingKeyMaterialProvider(
+- ReferenceCountedOpenSslContext.chooseX509KeyManager(getKeyManagers()), password, maxCachedEntries);
- }
-}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslEngineMap.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslEngineMap.java
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslCertificateException.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslCertificateException.java
deleted file mode 100644
-index 02131b4..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/OpenSslEngineMap.java
+index f20b2d3ba0..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslCertificateException.java
+++ /dev/null
-@@ -1,35 +0,0 @@
+@@ -1,81 +0,0 @@
-/*
-- * Copyright 2014 The Netty Project
+- * Copyright 2016 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
@@ -1041,261 +1526,76 @@ index 02131b4..0000000
- */
-package io.netty.handler.ssl;
-
--interface OpenSslEngineMap {
+-import io.netty.internal.tcnative.CertificateVerifier;
-
-- /**
-- * Remove the {@link OpenSslEngine} with the given {@code ssl} address and
-- * return it.
-- */
-- ReferenceCountedOpenSslEngine remove(long ssl);
--
-- /**
-- * Add a {@link OpenSslEngine} to this {@link OpenSslEngineMap}.
-- */
-- void add(ReferenceCountedOpenSslEngine engine);
--
-- /**
-- * Get the {@link OpenSslEngine} for the given {@code ssl} address.
-- */
-- ReferenceCountedOpenSslEngine get(long ssl);
--}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslExtendedKeyMaterialManager.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslExtendedKeyMaterialManager.java
-deleted file mode 100644
-index 38f6a7f..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/OpenSslExtendedKeyMaterialManager.java
-+++ /dev/null
-@@ -1,40 +0,0 @@
--/*
-- * Copyright 2016 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
--
--import javax.net.ssl.X509ExtendedKeyManager;
--import javax.security.auth.x500.X500Principal;
--
--final class OpenSslExtendedKeyMaterialManager extends OpenSslKeyMaterialManager {
--
-- private final X509ExtendedKeyManager keyManager;
--
-- OpenSslExtendedKeyMaterialManager(X509ExtendedKeyManager keyManager, String password) {
-- super(keyManager, password);
-- this.keyManager = keyManager;
-- }
--
-- @Override
-- protected String chooseClientAlias(ReferenceCountedOpenSslEngine engine, String[] keyTypes,
-- X500Principal[] issuer) {
-- return keyManager.chooseEngineClientAlias(keyTypes, issuer, engine);
-- }
--
-- @Override
-- protected String chooseServerAlias(ReferenceCountedOpenSslEngine engine, String type) {
-- return keyManager.chooseEngineServerAlias(type, null, engine);
-- }
--}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialManager.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialManager.java
-deleted file mode 100644
-index 2e48e8b..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialManager.java
-+++ /dev/null
-@@ -1,179 +0,0 @@
--/*
-- * Copyright 2016 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
--
--import io.netty.buffer.ByteBufAllocator;
--import io.netty.internal.tcnative.CertificateRequestedCallback;
--import io.netty.internal.tcnative.SSL;
--
--import javax.net.ssl.SSLException;
--import javax.net.ssl.X509KeyManager;
--import javax.security.auth.x500.X500Principal;
--import java.security.PrivateKey;
--import java.security.cert.X509Certificate;
--import java.util.HashMap;
--import java.util.HashSet;
--import java.util.Map;
--import java.util.Set;
--
--import static io.netty.handler.ssl.ReferenceCountedOpenSslContext.freeBio;
--import static io.netty.handler.ssl.ReferenceCountedOpenSslContext.toBIO;
+-import java.security.cert.CertificateException;
-
-/**
-- * Manages key material for {@link OpenSslEngine}s and so set the right {@link PrivateKey}s and
-- * {@link X509Certificate}s.
+- * A special {@link CertificateException} which allows to specify which error code is included in the
+- * SSL Record. This only work when {@link SslProvider#OPENSSL} or {@link SslProvider#OPENSSL_REFCNT} is used.
- */
--class OpenSslKeyMaterialManager {
--
-- // Code in this class is inspired by code of conscrypts:
-- // - https://android.googlesource.com/platform/external/
-- // conscrypt/+/master/src/main/java/org/conscrypt/OpenSSLEngineImpl.java
-- // - https://android.googlesource.com/platform/external/
-- // conscrypt/+/master/src/main/java/org/conscrypt/SSLParametersImpl.java
-- //
-- static final String KEY_TYPE_RSA = "RSA";
-- static final String KEY_TYPE_DH_RSA = "DH_RSA";
-- static final String KEY_TYPE_EC = "EC";
-- static final String KEY_TYPE_EC_EC = "EC_EC";
-- static final String KEY_TYPE_EC_RSA = "EC_RSA";
--
-- // key type mappings for types.
-- private static final Map<String, String> KEY_TYPES = new HashMap<String, String>();
-- static {
-- KEY_TYPES.put("RSA", KEY_TYPE_RSA);
-- KEY_TYPES.put("DHE_RSA", KEY_TYPE_RSA);
-- KEY_TYPES.put("ECDHE_RSA", KEY_TYPE_RSA);
-- KEY_TYPES.put("ECDHE_ECDSA", KEY_TYPE_EC);
-- KEY_TYPES.put("ECDH_RSA", KEY_TYPE_EC_RSA);
-- KEY_TYPES.put("ECDH_ECDSA", KEY_TYPE_EC_EC);
-- KEY_TYPES.put("DH_RSA", KEY_TYPE_DH_RSA);
-- }
+-public final class OpenSslCertificateException extends CertificateException {
+- private static final long serialVersionUID = 5542675253797129798L;
-
-- private final X509KeyManager keyManager;
-- private final String password;
+- private final int errorCode;
-
-- OpenSslKeyMaterialManager(X509KeyManager keyManager, String password) {
-- this.keyManager = keyManager;
-- this.password = password;
+- /**
+- * Construct a new exception with the
+- * <a href="https://www.openssl.org/docs/manmaster/apps/verify.html">error code</a>.
+- */
+- public OpenSslCertificateException(int errorCode) {
+- this((String) null, errorCode);
- }
-
-- void setKeyMaterial(ReferenceCountedOpenSslEngine engine) throws SSLException {
-- long ssl = engine.sslPointer();
-- String[] authMethods = SSL.authenticationMethods(ssl);
-- Set<String> aliases = new HashSet<String>(authMethods.length);
-- for (String authMethod : authMethods) {
-- String type = KEY_TYPES.get(authMethod);
-- if (type != null) {
-- String alias = chooseServerAlias(engine, type);
-- if (alias != null && aliases.add(alias)) {
-- setKeyMaterial(ssl, alias);
-- }
-- }
-- }
+- /**
+- * Construct a new exception with the msg and
+- * <a href="https://www.openssl.org/docs/manmaster/apps/verify.html">error code</a> .
+- */
+- public OpenSslCertificateException(String msg, int errorCode) {
+- super(msg);
+- this.errorCode = checkErrorCode(errorCode);
- }
-
-- CertificateRequestedCallback.KeyMaterial keyMaterial(ReferenceCountedOpenSslEngine engine, String[] keyTypes,
-- X500Principal[] issuer) throws SSLException {
-- String alias = chooseClientAlias(engine, keyTypes, issuer);
-- long keyBio = 0;
-- long keyCertChainBio = 0;
-- long pkey = 0;
-- long certChain = 0;
--
-- try {
-- // TODO: Should we cache these and so not need to do a memory copy all the time ?
-- X509Certificate[] certificates = keyManager.getCertificateChain(alias);
-- if (certificates == null || certificates.length == 0) {
-- return null;
-- }
--
-- PrivateKey key = keyManager.getPrivateKey(alias);
-- keyCertChainBio = toBIO(certificates);
-- certChain = SSL.parseX509Chain(keyCertChainBio);
-- if (key != null) {
-- keyBio = toBIO(key);
-- pkey = SSL.parsePrivateKey(keyBio, password);
-- }
-- CertificateRequestedCallback.KeyMaterial material = new CertificateRequestedCallback.KeyMaterial(
-- certChain, pkey);
--
-- // Reset to 0 so we do not free these. This is needed as the client certificate callback takes ownership
-- // of both the key and the certificate if they are returned from this method, and thus must not
-- // be freed here.
-- certChain = pkey = 0;
-- return material;
-- } catch (SSLException e) {
-- throw e;
-- } catch (Exception e) {
-- throw new SSLException(e);
-- } finally {
-- freeBio(keyBio);
-- freeBio(keyCertChainBio);
-- SSL.freePrivateKey(pkey);
-- SSL.freeX509Chain(certChain);
-- }
+- /**
+- * Construct a new exception with the msg, cause and
+- * <a href="https://www.openssl.org/docs/manmaster/apps/verify.html">error code</a> .
+- */
+- public OpenSslCertificateException(String message, Throwable cause, int errorCode) {
+- super(message, cause);
+- this.errorCode = checkErrorCode(errorCode);
- }
-
-- private void setKeyMaterial(long ssl, String alias) throws SSLException {
-- long keyBio = 0;
-- long keyCertChainBio = 0;
-- long keyCertChainBio2 = 0;
--
-- try {
-- // TODO: Should we cache these and so not need to do a memory copy all the time ?
-- X509Certificate[] certificates = keyManager.getCertificateChain(alias);
-- if (certificates == null || certificates.length == 0) {
-- return;
-- }
--
-- PrivateKey key = keyManager.getPrivateKey(alias);
--
-- // Only encode one time
-- PemEncoded encoded = PemX509Certificate.toPEM(ByteBufAllocator.DEFAULT, true, certificates);
-- try {
-- keyCertChainBio = toBIO(ByteBufAllocator.DEFAULT, encoded.retain());
-- keyCertChainBio2 = toBIO(ByteBufAllocator.DEFAULT, encoded.retain());
--
-- if (key != null) {
-- keyBio = toBIO(key);
-- }
-- SSL.setCertificateBio(ssl, keyCertChainBio, keyBio, password);
--
-- // We may have more then one cert in the chain so add all of them now.
-- SSL.setCertificateChainBio(ssl, keyCertChainBio2, true);
-- } finally {
-- encoded.release();
-- }
-- } catch (SSLException e) {
-- throw e;
-- } catch (Exception e) {
-- throw new SSLException(e);
-- } finally {
-- freeBio(keyBio);
-- freeBio(keyCertChainBio);
-- freeBio(keyCertChainBio2);
-- }
+- /**
+- * Construct a new exception with the cause and
+- * <a href="https://www.openssl.org/docs/manmaster/apps/verify.html">error code</a> .
+- */
+- public OpenSslCertificateException(Throwable cause, int errorCode) {
+- this(null, cause, errorCode);
- }
-
-- protected String chooseClientAlias(@SuppressWarnings("unused") ReferenceCountedOpenSslEngine engine,
-- String[] keyTypes, X500Principal[] issuer) {
-- return keyManager.chooseClientAlias(keyTypes, issuer, null);
+- /**
+- * Return the <a href="https://www.openssl.org/docs/man1.0.2/apps/verify.html">error code</a> to use.
+- */
+- public int errorCode() {
+- return errorCode;
- }
-
-- protected String chooseServerAlias(@SuppressWarnings("unused") ReferenceCountedOpenSslEngine engine, String type) {
-- return keyManager.chooseServerAlias(type, null, null);
+- private static int checkErrorCode(int errorCode) {
+- // Call OpenSsl.isAvailable() to ensure we try to load the native lib as CertificateVerifier.isValid(...)
+- // will depend on it. If loading fails we will just skip the validation.
+- if (OpenSsl.isAvailable() && !CertificateVerifier.isValid(errorCode)) {
+- throw new IllegalArgumentException("errorCode '" + errorCode +
+- "' invalid, see https://www.openssl.org/docs/man1.0.2/apps/verify.html.");
+- }
+- return errorCode;
- }
-}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerContext.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslServerContext.java
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslClientContext.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslClientContext.java
deleted file mode 100644
-index f57434b..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerContext.java
+index 7f9b39a8dd..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslClientContext.java
+++ /dev/null
-@@ -1,373 +0,0 @@
+@@ -1,208 +0,0 @@
-/*
- * Copyright 2014 The Netty Project
- *
@@ -1313,143 +1613,88 @@ index f57434b..0000000
- */
-package io.netty.handler.ssl;
-
--import io.netty.handler.ssl.ReferenceCountedOpenSslServerContext.ServerContext;
-import io.netty.internal.tcnative.SSL;
-
-import java.io.File;
+-import java.security.KeyStore;
-import java.security.PrivateKey;
-import java.security.cert.X509Certificate;
-
--import javax.net.ssl.KeyManager;
-import javax.net.ssl.KeyManagerFactory;
-import javax.net.ssl.SSLException;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.TrustManagerFactory;
-
--import static io.netty.handler.ssl.ReferenceCountedOpenSslServerContext.newSessionContext;
+-import static io.netty.handler.ssl.ReferenceCountedOpenSslClientContext.newSessionContext;
-
-/**
-- * A server-side {@link SslContext} which uses OpenSSL's SSL/TLS implementation.
+- * A client-side {@link SslContext} which uses OpenSSL's SSL/TLS implementation.
- * <p>This class will use a finalizer to ensure native resources are automatically cleaned up. To avoid finalizers
-- * and manually release the native memory see {@link ReferenceCountedOpenSslServerContext}.
+- * and manually release the native memory see {@link ReferenceCountedOpenSslClientContext}.
- */
--public final class OpenSslServerContext extends OpenSslContext {
-- private final OpenSslServerSessionContext sessionContext;
-- private final OpenSslKeyMaterialManager keyMaterialManager;
+-public final class OpenSslClientContext extends OpenSslContext {
+- private final OpenSslSessionContext sessionContext;
-
- /**
- * Creates a new instance.
-- *
-- * @param certChainFile an X.509 certificate chain file in PEM format
-- * @param keyFile a PKCS#8 private key file in PEM format
- * @deprecated use {@link SslContextBuilder}
- */
- @Deprecated
-- public OpenSslServerContext(File certChainFile, File keyFile) throws SSLException {
-- this(certChainFile, keyFile, null);
+- public OpenSslClientContext() throws SSLException {
+- this(null, null, null, null, null, null, null, IdentityCipherSuiteFilter.INSTANCE, null, 0, 0);
- }
-
- /**
- * Creates a new instance.
- *
-- * @param certChainFile an X.509 certificate chain file in PEM format
-- * @param keyFile a PKCS#8 private key file in PEM format
-- * @param keyPassword the password of the {@code keyFile}.
-- * {@code null} if it's not password-protected.
+- * @param certChainFile an X.509 certificate chain file in PEM format.
+- * {@code null} to use the system default
- * @deprecated use {@link SslContextBuilder}
- */
- @Deprecated
-- public OpenSslServerContext(File certChainFile, File keyFile, String keyPassword) throws SSLException {
-- this(certChainFile, keyFile, keyPassword, null, IdentityCipherSuiteFilter.INSTANCE,
-- ApplicationProtocolConfig.DISABLED, 0, 0);
+- public OpenSslClientContext(File certChainFile) throws SSLException {
+- this(certChainFile, null);
- }
-
- /**
- * Creates a new instance.
- *
-- * @param certChainFile an X.509 certificate chain file in PEM format
-- * @param keyFile a PKCS#8 private key file in PEM format
-- * @param keyPassword the password of the {@code keyFile}.
-- * {@code null} if it's not password-protected.
-- * @param ciphers the cipher suites to enable, in the order of preference.
-- * {@code null} to use the default cipher suites.
-- * @param apn Provides a means to configure parameters related to application protocol negotiation.
-- * @param sessionCacheSize the size of the cache used for storing SSL session objects.
-- * {@code 0} to use the default value.
-- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
-- * {@code 0} to use the default value.
-- * @deprecated use {@link SslContextBuilder}
-- */
-- @Deprecated
-- public OpenSslServerContext(
-- File certChainFile, File keyFile, String keyPassword,
-- Iterable<String> ciphers, ApplicationProtocolConfig apn,
-- long sessionCacheSize, long sessionTimeout) throws SSLException {
-- this(certChainFile, keyFile, keyPassword, ciphers, IdentityCipherSuiteFilter.INSTANCE,
-- apn, sessionCacheSize, sessionTimeout);
-- }
--
-- /**
-- * Creates a new instance.
-- *
-- * @param certChainFile an X.509 certificate chain file in PEM format
-- * @param keyFile a PKCS#8 private key file in PEM format
-- * @param keyPassword the password of the {@code keyFile}.
-- * {@code null} if it's not password-protected.
-- * @param ciphers the cipher suites to enable, in the order of preference.
-- * {@code null} to use the default cipher suites.
-- * @param nextProtocols the application layer protocols to accept, in the order of preference.
-- * {@code null} to disable TLS NPN/ALPN extension.
-- * @param sessionCacheSize the size of the cache used for storing SSL session objects.
-- * {@code 0} to use the default value.
-- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
-- * {@code 0} to use the default value.
+- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
+- * that verifies the certificates sent from servers.
+- * {@code null} to use the default.
- * @deprecated use {@link SslContextBuilder}
- */
- @Deprecated
-- public OpenSslServerContext(
-- File certChainFile, File keyFile, String keyPassword,
-- Iterable<String> ciphers, Iterable<String> nextProtocols,
-- long sessionCacheSize, long sessionTimeout) throws SSLException {
-- this(certChainFile, keyFile, keyPassword, ciphers,
-- toApplicationProtocolConfig(nextProtocols), sessionCacheSize, sessionTimeout);
+- public OpenSslClientContext(TrustManagerFactory trustManagerFactory) throws SSLException {
+- this(null, trustManagerFactory);
- }
-
- /**
- * Creates a new instance.
- *
-- * @param certChainFile an X.509 certificate chain file in PEM format
-- * @param keyFile a PKCS#8 private key file in PEM format
-- * @param keyPassword the password of the {@code keyFile}.
-- * {@code null} if it's not password-protected.
-- * @param ciphers the cipher suites to enable, in the order of preference.
-- * {@code null} to use the default cipher suites.
-- * @param config Application protocol config.
-- * @param sessionCacheSize the size of the cache used for storing SSL session objects.
-- * {@code 0} to use the default value.
-- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
-- * {@code 0} to use the default value.
+- * @param certChainFile an X.509 certificate chain file in PEM format.
+- * {@code null} to use the system default
+- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
+- * that verifies the certificates sent from servers.
+- * {@code null} to use the default.
- * @deprecated use {@link SslContextBuilder}
- */
- @Deprecated
-- public OpenSslServerContext(
-- File certChainFile, File keyFile, String keyPassword, TrustManagerFactory trustManagerFactory,
-- Iterable<String> ciphers, ApplicationProtocolConfig config,
-- long sessionCacheSize, long sessionTimeout) throws SSLException {
-- this(certChainFile, keyFile, keyPassword, trustManagerFactory, ciphers,
-- toNegotiator(config), sessionCacheSize, sessionTimeout);
+- public OpenSslClientContext(File certChainFile, TrustManagerFactory trustManagerFactory) throws SSLException {
+- this(certChainFile, trustManagerFactory, null, null, null, null, null,
+- IdentityCipherSuiteFilter.INSTANCE, null, 0, 0);
- }
-
- /**
- * Creates a new instance.
- *
- * @param certChainFile an X.509 certificate chain file in PEM format
-- * @param keyFile a PKCS#8 private key file in PEM format
-- * @param keyPassword the password of the {@code keyFile}.
-- * {@code null} if it's not password-protected.
+- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
+- * that verifies the certificates sent from servers.
+- * {@code null} to use the default..
- * @param ciphers the cipher suites to enable, in the order of preference.
- * {@code null} to use the default cipher suites.
-- * @param apn Application protocol negotiator.
+- * @param apn Provides a means to configure parameters related to application protocol negotiation.
- * @param sessionCacheSize the size of the cache used for storing SSL session objects.
- * {@code 0} to use the default value.
- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
@@ -1457,21 +1702,20 @@ index f57434b..0000000
- * @deprecated use {@link SslContextBuilder}
- */
- @Deprecated
-- public OpenSslServerContext(
-- File certChainFile, File keyFile, String keyPassword, TrustManagerFactory trustManagerFactory,
-- Iterable<String> ciphers, OpenSslApplicationProtocolNegotiator apn,
-- long sessionCacheSize, long sessionTimeout) throws SSLException {
-- this(null, trustManagerFactory, certChainFile, keyFile, keyPassword, null,
-- ciphers, null, apn, sessionCacheSize, sessionTimeout);
+- public OpenSslClientContext(File certChainFile, TrustManagerFactory trustManagerFactory, Iterable<String> ciphers,
+- ApplicationProtocolConfig apn, long sessionCacheSize, long sessionTimeout)
+- throws SSLException {
+- this(certChainFile, trustManagerFactory, null, null, null, null, ciphers, IdentityCipherSuiteFilter.INSTANCE,
+- apn, sessionCacheSize, sessionTimeout);
- }
-
- /**
- * Creates a new instance.
- *
- * @param certChainFile an X.509 certificate chain file in PEM format
-- * @param keyFile a PKCS#8 private key file in PEM format
-- * @param keyPassword the password of the {@code keyFile}.
-- * {@code null} if it's not password-protected.
+- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
+- * that verifies the certificates sent from servers.
+- * {@code null} to use the default..
- * @param ciphers the cipher suites to enable, in the order of preference.
- * {@code null} to use the default cipher suites.
- * @param cipherFilter a filter to apply over the supplied list of ciphers
@@ -1483,129 +1727,38 @@ index f57434b..0000000
- * @deprecated use {@link SslContextBuilder}
- */
- @Deprecated
-- public OpenSslServerContext(
-- File certChainFile, File keyFile, String keyPassword,
-- Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
-- long sessionCacheSize, long sessionTimeout) throws SSLException {
-- this(null, null, certChainFile, keyFile, keyPassword, null,
+- public OpenSslClientContext(File certChainFile, TrustManagerFactory trustManagerFactory, Iterable<String> ciphers,
+- CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
+- long sessionCacheSize, long sessionTimeout) throws SSLException {
+- this(certChainFile, trustManagerFactory, null, null, null, null,
- ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout);
- }
-
- /**
- * Creates a new instance.
-- *
- * @param trustCertCollectionFile an X.509 certificate collection file in PEM format.
-- * This provides the certificate collection used for mutual authentication.
- * {@code null} to use the system default
- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
-- * that verifies the certificates sent from clients.
+- * that verifies the certificates sent from servers.
- * {@code null} to use the default or the results of parsing
-- * {@code trustCertCollectionFile}.
-- * @param keyCertChainFile an X.509 certificate chain file in PEM format
-- * @param keyFile a PKCS#8 private key file in PEM format
-- * @param keyPassword the password of the {@code keyFile}.
-- * {@code null} if it's not password-protected.
-- * @param keyManagerFactory the {@link KeyManagerFactory} that provides the {@link KeyManager}s
-- * that is used to encrypt data being sent to clients.
-- * {@code null} to use the default or the results of parsing
-- * {@code keyCertChainFile} and {@code keyFile}.
-- * @param ciphers the cipher suites to enable, in the order of preference.
-- * {@code null} to use the default cipher suites.
-- * @param cipherFilter a filter to apply over the supplied list of ciphers
-- * Only required if {@code provider} is {@link SslProvider#JDK}
-- * @param config Provides a means to configure parameters related to application protocol negotiation.
-- * @param sessionCacheSize the size of the cache used for storing SSL session objects.
-- * {@code 0} to use the default value.
-- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
-- * {@code 0} to use the default value.
-- * @deprecated use {@link SslContextBuilder}
-- */
-- @Deprecated
-- public OpenSslServerContext(
-- File trustCertCollectionFile, TrustManagerFactory trustManagerFactory,
-- File keyCertChainFile, File keyFile, String keyPassword, KeyManagerFactory keyManagerFactory,
-- Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig config,
-- long sessionCacheSize, long sessionTimeout) throws SSLException {
-- this(trustCertCollectionFile, trustManagerFactory, keyCertChainFile, keyFile, keyPassword, keyManagerFactory,
-- ciphers, cipherFilter, toNegotiator(config), sessionCacheSize, sessionTimeout);
-- }
--
-- /**
-- * Creates a new instance.
-- *
-- * @param certChainFile an X.509 certificate chain file in PEM format
-- * @param keyFile a PKCS#8 private key file in PEM format
-- * @param keyPassword the password of the {@code keyFile}.
-- * {@code null} if it's not password-protected.
-- * @param ciphers the cipher suites to enable, in the order of preference.
-- * {@code null} to use the default cipher suites.
-- * @param cipherFilter a filter to apply over the supplied list of ciphers
-- * @param config Application protocol config.
-- * @param sessionCacheSize the size of the cache used for storing SSL session objects.
-- * {@code 0} to use the default value.
-- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
-- * {@code 0} to use the default value.
-- * @deprecated use {@link SslContextBuilder}
-- */
-- @Deprecated
-- public OpenSslServerContext(File certChainFile, File keyFile, String keyPassword,
-- TrustManagerFactory trustManagerFactory, Iterable<String> ciphers,
-- CipherSuiteFilter cipherFilter, ApplicationProtocolConfig config,
-- long sessionCacheSize, long sessionTimeout) throws SSLException {
-- this(null, trustManagerFactory, certChainFile, keyFile, keyPassword, null, ciphers, cipherFilter,
-- toNegotiator(config), sessionCacheSize, sessionTimeout);
-- }
--
-- /**
-- * Creates a new instance.
-- *
-- * @param certChainFile an X.509 certificate chain file in PEM format
-- * @param keyFile a PKCS#8 private key file in PEM format
-- * @param keyPassword the password of the {@code keyFile}.
-- * {@code null} if it's not password-protected.
-- * @param ciphers the cipher suites to enable, in the order of preference.
-- * {@code null} to use the default cipher suites.
-- * @param cipherFilter a filter to apply over the supplied list of ciphers
-- * @param apn Application protocol negotiator.
-- * @param sessionCacheSize the size of the cache used for storing SSL session objects.
-- * {@code 0} to use the default value.
-- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
-- * {@code 0} to use the default value.
-- * @deprecated use {@link SslContextBuilder}}
-- */
-- @Deprecated
-- public OpenSslServerContext(
-- File certChainFile, File keyFile, String keyPassword, TrustManagerFactory trustManagerFactory,
-- Iterable<String> ciphers, CipherSuiteFilter cipherFilter, OpenSslApplicationProtocolNegotiator apn,
-- long sessionCacheSize, long sessionTimeout) throws SSLException {
-- this(null, trustManagerFactory, certChainFile, keyFile, keyPassword, null, ciphers, cipherFilter,
-- apn, sessionCacheSize, sessionTimeout);
-- }
--
-- /**
-- * Creates a new instance.
-- *
-- *
-- * @param trustCertCollectionFile an X.509 certificate collection file in PEM format.
-- * This provides the certificate collection used for mutual authentication.
+- * {@code trustCertCollectionFile}
+- * @param keyCertChainFile an X.509 certificate chain file in PEM format.
+- * This provides the public key for mutual authentication.
- * {@code null} to use the system default
-- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
-- * that verifies the certificates sent from clients.
-- * {@code null} to use the default or the results of parsing
-- * {@code trustCertCollectionFile}.
-- * @param keyCertChainFile an X.509 certificate chain file in PEM format
-- * @param keyFile a PKCS#8 private key file in PEM format
+- * @param keyFile a PKCS#8 private key file in PEM format.
+- * This provides the private key for mutual authentication.
+- * {@code null} for no mutual authentication.
- * @param keyPassword the password of the {@code keyFile}.
- * {@code null} if it's not password-protected.
-- * @param keyManagerFactory the {@link KeyManagerFactory} that provides the {@link KeyManager}s
-- * that is used to encrypt data being sent to clients.
+- * Ignored if {@code keyFile} is {@code null}.
+- * @param keyManagerFactory the {@link KeyManagerFactory} that provides the {@link javax.net.ssl.KeyManager}s
+- * that is used to encrypt data being sent to servers.
- * {@code null} to use the default or the results of parsing
- * {@code keyCertChainFile} and {@code keyFile}.
- * @param ciphers the cipher suites to enable, in the order of preference.
- * {@code null} to use the default cipher suites.
- * @param cipherFilter a filter to apply over the supplied list of ciphers
-- * Only required if {@code provider} is {@link SslProvider#JDK}
-- * @param apn Application Protocol Negotiator object
+- * @param apn Application Protocol Negotiator object.
- * @param sessionCacheSize the size of the cache used for storing SSL session objects.
- * {@code 0} to use the default value.
- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
@@ -1613,44 +1766,31 @@ index f57434b..0000000
- * @deprecated use {@link SslContextBuilder}
- */
- @Deprecated
-- public OpenSslServerContext(
-- File trustCertCollectionFile, TrustManagerFactory trustManagerFactory,
-- File keyCertChainFile, File keyFile, String keyPassword, KeyManagerFactory keyManagerFactory,
-- Iterable<String> ciphers, CipherSuiteFilter cipherFilter, OpenSslApplicationProtocolNegotiator apn,
-- long sessionCacheSize, long sessionTimeout) throws SSLException {
+- public OpenSslClientContext(File trustCertCollectionFile, TrustManagerFactory trustManagerFactory,
+- File keyCertChainFile, File keyFile, String keyPassword,
+- KeyManagerFactory keyManagerFactory, Iterable<String> ciphers,
+- CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
+- long sessionCacheSize, long sessionTimeout)
+- throws SSLException {
- this(toX509CertificatesInternal(trustCertCollectionFile), trustManagerFactory,
- toX509CertificatesInternal(keyCertChainFile), toPrivateKeyInternal(keyFile, keyPassword),
-- keyPassword, keyManagerFactory, ciphers, cipherFilter,
-- apn, sessionCacheSize, sessionTimeout, ClientAuth.NONE, null, false, false);
-- }
--
-- OpenSslServerContext(
-- X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory,
-- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory,
-- Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
-- long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[] protocols, boolean startTls,
-- boolean enableOcsp) throws SSLException {
-- this(trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory, ciphers,
-- cipherFilter, toNegotiator(apn), sessionCacheSize, sessionTimeout, clientAuth, protocols, startTls,
-- enableOcsp);
+- keyPassword, keyManagerFactory, ciphers, cipherFilter, apn, null, sessionCacheSize,
+- sessionTimeout, false, KeyStore.getDefaultType());
- }
-
-- @SuppressWarnings("deprecation")
-- private OpenSslServerContext(
-- X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory,
-- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory,
-- Iterable<String> ciphers, CipherSuiteFilter cipherFilter, OpenSslApplicationProtocolNegotiator apn,
-- long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[] protocols, boolean startTls,
-- boolean enableOcsp) throws SSLException {
-- super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, SSL.SSL_MODE_SERVER, keyCertChain,
-- clientAuth, protocols, startTls, enableOcsp);
-- // Create a new SSL_CTX and configure it.
+- OpenSslClientContext(X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory,
+- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword,
+- KeyManagerFactory keyManagerFactory, Iterable<String> ciphers,
+- CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, String[] protocols,
+- long sessionCacheSize, long sessionTimeout, boolean enableOcsp, String keyStore)
+- throws SSLException {
+- super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, SSL.SSL_MODE_CLIENT, keyCertChain,
+- ClientAuth.NONE, protocols, false, enableOcsp);
- boolean success = false;
- try {
-- ServerContext context = newSessionContext(this, ctx, engineMap, trustCertCollection, trustManagerFactory,
-- keyCertChain, key, keyPassword, keyManagerFactory);
-- sessionContext = context.sessionContext;
-- keyMaterialManager = context.keyMaterialManager;
+- OpenSslKeyMaterialProvider.validateKeyMaterialSupported(keyCertChain, key, keyPassword);
+- sessionContext = newSessionContext(this, ctx, engineMap, trustCertCollection, trustManagerFactory,
+- keyCertChain, key, keyPassword, keyManagerFactory, keyStore);
- success = true;
- } finally {
- if (!success) {
@@ -1660,21 +1800,16 @@ index f57434b..0000000
- }
-
- @Override
-- public OpenSslServerSessionContext sessionContext() {
+- public OpenSslSessionContext sessionContext() {
- return sessionContext;
- }
--
-- @Override
-- OpenSslKeyMaterialManager keyMaterialManager() {
-- return keyMaterialManager;
-- }
-}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerSessionContext.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslServerSessionContext.java
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslContext.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslContext.java
deleted file mode 100644
-index 8c92deb..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerSessionContext.java
+index f18c0643fc..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslContext.java
+++ /dev/null
-@@ -1,124 +0,0 @@
+@@ -1,58 +0,0 @@
-/*
- * Copyright 2014 The Netty Project
- *
@@ -1692,119 +1827,53 @@ index 8c92deb..0000000
- */
-package io.netty.handler.ssl;
-
--import io.netty.internal.tcnative.SSL;
--import io.netty.internal.tcnative.SSLContext;
+-import io.netty.buffer.ByteBufAllocator;
-
--import java.util.concurrent.locks.Lock;
+-import java.security.cert.Certificate;
-
+-import javax.net.ssl.SSLEngine;
+-import javax.net.ssl.SSLException;
-
-/**
-- * {@link OpenSslSessionContext} implementation which offers extra methods which are only useful for the server-side.
+- * This class will use a finalizer to ensure native resources are automatically cleaned up. To avoid finalizers
+- * and manually release the native memory see {@link ReferenceCountedOpenSslContext}.
- */
--public final class OpenSslServerSessionContext extends OpenSslSessionContext {
-- OpenSslServerSessionContext(ReferenceCountedOpenSslContext context) {
-- super(context);
-- }
--
-- @Override
-- public void setSessionTimeout(int seconds) {
-- if (seconds < 0) {
-- throw new IllegalArgumentException();
-- }
-- Lock writerLock = context.ctxLock.writeLock();
-- writerLock.lock();
-- try {
-- SSLContext.setSessionCacheTimeout(context.ctx, seconds);
-- } finally {
-- writerLock.unlock();
-- }
-- }
--
-- @Override
-- public int getSessionTimeout() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
-- try {
-- return (int) SSLContext.getSessionCacheTimeout(context.ctx);
-- } finally {
-- readerLock.unlock();
-- }
-- }
--
-- @Override
-- public void setSessionCacheSize(int size) {
-- if (size < 0) {
-- throw new IllegalArgumentException();
-- }
-- Lock writerLock = context.ctxLock.writeLock();
-- writerLock.lock();
-- try {
-- SSLContext.setSessionCacheSize(context.ctx, size);
-- } finally {
-- writerLock.unlock();
-- }
+-public abstract class OpenSslContext extends ReferenceCountedOpenSslContext {
+- OpenSslContext(Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apnCfg,
+- long sessionCacheSize, long sessionTimeout, int mode, Certificate[] keyCertChain,
+- ClientAuth clientAuth, String[] protocols, boolean startTls, boolean enableOcsp)
+- throws SSLException {
+- super(ciphers, cipherFilter, apnCfg, sessionCacheSize, sessionTimeout, mode, keyCertChain,
+- clientAuth, protocols, startTls, enableOcsp, false);
- }
-
-- @Override
-- public int getSessionCacheSize() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
-- try {
-- return (int) SSLContext.getSessionCacheSize(context.ctx);
-- } finally {
-- readerLock.unlock();
-- }
+- OpenSslContext(Iterable<String> ciphers, CipherSuiteFilter cipherFilter,
+- OpenSslApplicationProtocolNegotiator apn, long sessionCacheSize,
+- long sessionTimeout, int mode, Certificate[] keyCertChain,
+- ClientAuth clientAuth, String[] protocols, boolean startTls,
+- boolean enableOcsp) throws SSLException {
+- super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, mode, keyCertChain, clientAuth, protocols,
+- startTls, enableOcsp, false);
- }
-
- @Override
-- public void setSessionCacheEnabled(boolean enabled) {
-- long mode = enabled ? SSL.SSL_SESS_CACHE_SERVER : SSL.SSL_SESS_CACHE_OFF;
--
-- Lock writerLock = context.ctxLock.writeLock();
-- writerLock.lock();
-- try {
-- SSLContext.setSessionCacheMode(context.ctx, mode);
-- } finally {
-- writerLock.unlock();
-- }
+- final SSLEngine newEngine0(ByteBufAllocator alloc, String peerHost, int peerPort, boolean jdkCompatibilityMode) {
+- return new OpenSslEngine(this, alloc, peerHost, peerPort, jdkCompatibilityMode);
- }
-
- @Override
-- public boolean isSessionCacheEnabled() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
-- try {
-- return SSLContext.getSessionCacheMode(context.ctx) == SSL.SSL_SESS_CACHE_SERVER;
-- } finally {
-- readerLock.unlock();
-- }
-- }
--
-- /**
-- * Set the context within which session be reused (server side only)
-- * See <a href="http://www.openssl.org/docs/ssl/SSL_CTX_set_session_id_context.html">
-- * man SSL_CTX_set_session_id_context</a>
-- *
-- * @param sidCtx can be any kind of binary data, it is therefore possible to use e.g. the name
-- * of the application and/or the hostname and/or service name
-- * @return {@code true} if success, {@code false} otherwise.
-- */
-- public boolean setSessionIdContext(byte[] sidCtx) {
-- Lock writerLock = context.ctxLock.writeLock();
-- writerLock.lock();
-- try {
-- return SSLContext.setSessionIdContext(context.ctx, sidCtx);
-- } finally {
-- writerLock.unlock();
-- }
+- @SuppressWarnings("FinalizeDeclaration")
+- protected final void finalize() throws Throwable {
+- super.finalize();
+- OpenSsl.releaseIfNeeded(this);
- }
-}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionContext.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionContext.java
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslEngine.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslEngine.java
deleted file mode 100644
-index 846a968..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionContext.java
+index a700dabf39..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslEngine.java
+++ /dev/null
-@@ -1,137 +0,0 @@
+@@ -1,41 +0,0 @@
-/*
- * Copyright 2014 The Netty Project
- *
@@ -1822,132 +1891,36 @@ index 846a968..0000000
- */
-package io.netty.handler.ssl;
-
--import io.netty.util.internal.ObjectUtil;
--import io.netty.internal.tcnative.SSL;
--import io.netty.internal.tcnative.SSLContext;
--import io.netty.internal.tcnative.SessionTicketKey;
+-import io.netty.buffer.ByteBufAllocator;
-
--import javax.net.ssl.SSLSession;
--import javax.net.ssl.SSLSessionContext;
--import java.util.Arrays;
--import java.util.Enumeration;
--import java.util.NoSuchElementException;
--import java.util.concurrent.locks.Lock;
+-import javax.net.ssl.SSLEngine;
-
-/**
-- * OpenSSL specific {@link SSLSessionContext} implementation.
+- * Implements a {@link SSLEngine} using
+- * <a href="https://www.openssl.org/docs/crypto/BIO_s_bio.html#EXAMPLE">OpenSSL BIO abstractions</a>.
+- * <p>
+- * This class will use a finalizer to ensure native resources are automatically cleaned up. To avoid finalizers
+- * and manually release the native memory see {@link ReferenceCountedOpenSslEngine}.
- */
--public abstract class OpenSslSessionContext implements SSLSessionContext {
-- private static final Enumeration<byte[]> EMPTY = new EmptyEnumeration();
--
-- private final OpenSslSessionStats stats;
-- final ReferenceCountedOpenSslContext context;
--
-- // IMPORTANT: We take the OpenSslContext and not just the long (which points the native instance) to prevent
-- // the GC to collect OpenSslContext as this would also free the pointer and so could result in a
-- // segfault when the user calls any of the methods here that try to pass the pointer down to the native
-- // level.
-- OpenSslSessionContext(ReferenceCountedOpenSslContext context) {
-- this.context = context;
-- stats = new OpenSslSessionStats(context);
-- }
--
-- @Override
-- public SSLSession getSession(byte[] bytes) {
-- if (bytes == null) {
-- throw new NullPointerException("bytes");
-- }
-- return null;
+-public final class OpenSslEngine extends ReferenceCountedOpenSslEngine {
+- OpenSslEngine(OpenSslContext context, ByteBufAllocator alloc, String peerHost, int peerPort,
+- boolean jdkCompatibilityMode) {
+- super(context, alloc, peerHost, peerPort, jdkCompatibilityMode, false);
- }
-
- @Override
-- public Enumeration<byte[]> getIds() {
-- return EMPTY;
-- }
--
-- /**
-- * Sets the SSL session ticket keys of this context.
-- * @deprecated use {@link #setTicketKeys(OpenSslSessionTicketKey...)}.
-- */
-- @Deprecated
-- public void setTicketKeys(byte[] keys) {
-- if (keys.length % SessionTicketKey.TICKET_KEY_SIZE != 0) {
-- throw new IllegalArgumentException("keys.length % " + SessionTicketKey.TICKET_KEY_SIZE + " != 0");
-- }
-- SessionTicketKey[] tickets = new SessionTicketKey[keys.length / SessionTicketKey.TICKET_KEY_SIZE];
-- for (int i = 0, a = 0; i < tickets.length; i++) {
-- byte[] name = Arrays.copyOfRange(keys, a, SessionTicketKey.NAME_SIZE);
-- a += SessionTicketKey.NAME_SIZE;
-- byte[] hmacKey = Arrays.copyOfRange(keys, a, SessionTicketKey.HMAC_KEY_SIZE);
-- i += SessionTicketKey.HMAC_KEY_SIZE;
-- byte[] aesKey = Arrays.copyOfRange(keys, a, SessionTicketKey.AES_KEY_SIZE);
-- a += SessionTicketKey.AES_KEY_SIZE;
-- tickets[i] = new SessionTicketKey(name, hmacKey, aesKey);
-- }
-- Lock writerLock = context.ctxLock.writeLock();
-- writerLock.lock();
-- try {
-- SSLContext.clearOptions(context.ctx, SSL.SSL_OP_NO_TICKET);
-- SSLContext.setSessionTicketKeys(context.ctx, tickets);
-- } finally {
-- writerLock.unlock();
-- }
-- }
--
-- /**
-- * Sets the SSL session ticket keys of this context.
-- */
-- public void setTicketKeys(OpenSslSessionTicketKey... keys) {
-- ObjectUtil.checkNotNull(keys, "keys");
-- SessionTicketKey[] ticketKeys = new SessionTicketKey[keys.length];
-- for (int i = 0; i < ticketKeys.length; i++) {
-- ticketKeys[i] = keys[i].key;
-- }
-- Lock writerLock = context.ctxLock.writeLock();
-- writerLock.lock();
-- try {
-- SSLContext.clearOptions(context.ctx, SSL.SSL_OP_NO_TICKET);
-- SSLContext.setSessionTicketKeys(context.ctx, ticketKeys);
-- } finally {
-- writerLock.unlock();
-- }
-- }
--
-- /**
-- * Enable or disable caching of SSL sessions.
-- */
-- public abstract void setSessionCacheEnabled(boolean enabled);
--
-- /**
-- * Return {@code true} if caching of SSL sessions is enabled, {@code false} otherwise.
-- */
-- public abstract boolean isSessionCacheEnabled();
--
-- /**
-- * Returns the stats of this context.
-- */
-- public OpenSslSessionStats stats() {
-- return stats;
-- }
--
-- private static final class EmptyEnumeration implements Enumeration<byte[]> {
-- @Override
-- public boolean hasMoreElements() {
-- return false;
-- }
--
-- @Override
-- public byte[] nextElement() {
-- throw new NoSuchElementException();
-- }
+- @SuppressWarnings("FinalizeDeclaration")
+- protected void finalize() throws Throwable {
+- super.finalize();
+- OpenSsl.releaseIfNeeded(this);
- }
-}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionStats.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionStats.java
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslEngineMap.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslEngineMap.java
deleted file mode 100644
-index f49b95f..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionStats.java
+index 02131b4b26..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslEngineMap.java
+++ /dev/null
-@@ -1,253 +0,0 @@
+@@ -1,35 +0,0 @@
-/*
- * Copyright 2014 The Netty Project
- *
@@ -1963,252 +1936,524 @@ index f49b95f..0000000
- * License for the specific language governing permissions and limitations
- * under the License.
- */
--
-package io.netty.handler.ssl;
-
--import io.netty.internal.tcnative.SSLContext;
+-interface OpenSslEngineMap {
-
--import java.util.concurrent.locks.Lock;
+- /**
+- * Remove the {@link OpenSslEngine} with the given {@code ssl} address and
+- * return it.
+- */
+- ReferenceCountedOpenSslEngine remove(long ssl);
-
--/**
-- * Stats exposed by an OpenSSL session context.
+- /**
+- * Add a {@link OpenSslEngine} to this {@link OpenSslEngineMap}.
+- */
+- void add(ReferenceCountedOpenSslEngine engine);
+-
+- /**
+- * Get the {@link OpenSslEngine} for the given {@code ssl} address.
+- */
+- ReferenceCountedOpenSslEngine get(long ssl);
+-}
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialManager.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialManager.java
+deleted file mode 100644
+index 7acbf70cfe..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialManager.java
++++ /dev/null
+@@ -1,127 +0,0 @@
+-/*
+- * Copyright 2016 The Netty Project
- *
-- * @see <a href="https://www.openssl.org/docs/manmaster/man3/SSL_CTX_sess_number.html">SSL_CTX_sess_number</a>
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- * http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
- */
--public final class OpenSslSessionStats {
+-package io.netty.handler.ssl;
-
-- private final ReferenceCountedOpenSslContext context;
+-import javax.net.ssl.SSLException;
+-import javax.net.ssl.X509ExtendedKeyManager;
+-import javax.net.ssl.X509KeyManager;
+-import javax.security.auth.x500.X500Principal;
+-import java.security.PrivateKey;
+-import java.security.cert.X509Certificate;
+-import java.util.HashMap;
+-import java.util.HashSet;
+-import java.util.Map;
+-import java.util.Set;
-
-- // IMPORTANT: We take the OpenSslContext and not just the long (which points the native instance) to prevent
-- // the GC to collect OpenSslContext as this would also free the pointer and so could result in a
-- // segfault when the user calls any of the methods here that try to pass the pointer down to the native
-- // level.
-- OpenSslSessionStats(ReferenceCountedOpenSslContext context) {
-- this.context = context;
+-
+-/**
+- * Manages key material for {@link OpenSslEngine}s and so set the right {@link PrivateKey}s and
+- * {@link X509Certificate}s.
+- */
+-final class OpenSslKeyMaterialManager {
+-
+- // Code in this class is inspired by code of conscrypts:
+- // - https://android.googlesource.com/platform/external/
+- // conscrypt/+/master/src/main/java/org/conscrypt/OpenSSLEngineImpl.java
+- // - https://android.googlesource.com/platform/external/
+- // conscrypt/+/master/src/main/java/org/conscrypt/SSLParametersImpl.java
+- //
+- static final String KEY_TYPE_RSA = "RSA";
+- static final String KEY_TYPE_DH_RSA = "DH_RSA";
+- static final String KEY_TYPE_EC = "EC";
+- static final String KEY_TYPE_EC_EC = "EC_EC";
+- static final String KEY_TYPE_EC_RSA = "EC_RSA";
+-
+- // key type mappings for types.
+- private static final Map<String, String> KEY_TYPES = new HashMap<String, String>();
+- static {
+- KEY_TYPES.put("RSA", KEY_TYPE_RSA);
+- KEY_TYPES.put("DHE_RSA", KEY_TYPE_RSA);
+- KEY_TYPES.put("ECDHE_RSA", KEY_TYPE_RSA);
+- KEY_TYPES.put("ECDHE_ECDSA", KEY_TYPE_EC);
+- KEY_TYPES.put("ECDH_RSA", KEY_TYPE_EC_RSA);
+- KEY_TYPES.put("ECDH_ECDSA", KEY_TYPE_EC_EC);
+- KEY_TYPES.put("DH_RSA", KEY_TYPE_DH_RSA);
- }
-
-- /**
-- * Returns the current number of sessions in the internal session cache.
-- */
-- public long number() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
-- try {
-- return SSLContext.sessionNumber(context.ctx);
-- } finally {
-- readerLock.unlock();
-- }
+- private final OpenSslKeyMaterialProvider provider;
+-
+- OpenSslKeyMaterialManager(OpenSslKeyMaterialProvider provider) {
+- this.provider = provider;
- }
-
-- /**
-- * Returns the number of started SSL/TLS handshakes in client mode.
-- */
-- public long connect() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
-- try {
-- return SSLContext.sessionConnect(context.ctx);
-- } finally {
-- readerLock.unlock();
+- void setKeyMaterialServerSide(ReferenceCountedOpenSslEngine engine) throws SSLException {
+- String[] authMethods = engine.authMethods();
+- if (authMethods.length == 0) {
+- return;
+- }
+- Set<String> aliases = new HashSet<String>(authMethods.length);
+- for (String authMethod : authMethods) {
+- String type = KEY_TYPES.get(authMethod);
+- if (type != null) {
+- String alias = chooseServerAlias(engine, type);
+- if (alias != null && aliases.add(alias)) {
+- if (!setKeyMaterial(engine, alias)) {
+- return;
+- }
+- }
+- }
- }
- }
-
-- /**
-- * Returns the number of successfully established SSL/TLS sessions in client mode.
-- */
-- public long connectGood() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
-- try {
-- return SSLContext.sessionConnectGood(context.ctx);
-- } finally {
-- readerLock.unlock();
+- void setKeyMaterialClientSide(ReferenceCountedOpenSslEngine engine, String[] keyTypes,
+- X500Principal[] issuer) throws SSLException {
+- String alias = chooseClientAlias(engine, keyTypes, issuer);
+- // Only try to set the keymaterial if we have a match. This is also consistent with what OpenJDK does:
+- // http://hg.openjdk.java.net/jdk/jdk11/file/76072a077ee1/
+- // src/java.base/share/classes/sun/security/ssl/CertificateRequest.java#l362
+- if (alias != null) {
+- setKeyMaterial(engine, alias);
- }
- }
-
-- /**
-- * Returns the number of start renegotiations in client mode.
-- */
-- public long connectRenegotiate() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
+- private boolean setKeyMaterial(ReferenceCountedOpenSslEngine engine, String alias) throws SSLException {
+- OpenSslKeyMaterial keyMaterial = null;
- try {
-- return SSLContext.sessionConnectRenegotiate(context.ctx);
+- keyMaterial = provider.chooseKeyMaterial(engine.alloc, alias);
+- return keyMaterial == null || engine.setKeyMaterial(keyMaterial);
+- } catch (SSLException e) {
+- throw e;
+- } catch (Exception e) {
+- throw new SSLException(e);
- } finally {
-- readerLock.unlock();
+- if (keyMaterial != null) {
+- keyMaterial.release();
+- }
+- }
+- }
+- private String chooseClientAlias(ReferenceCountedOpenSslEngine engine,
+- String[] keyTypes, X500Principal[] issuer) {
+- X509KeyManager manager = provider.keyManager();
+- if (manager instanceof X509ExtendedKeyManager) {
+- return ((X509ExtendedKeyManager) manager).chooseEngineClientAlias(keyTypes, issuer, engine);
- }
+- return manager.chooseClientAlias(keyTypes, issuer, null);
- }
-
-- /**
-- * Returns the number of started SSL/TLS handshakes in server mode.
-- */
-- public long accept() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
-- try {
-- return SSLContext.sessionAccept(context.ctx);
-- } finally {
-- readerLock.unlock();
+- private String chooseServerAlias(ReferenceCountedOpenSslEngine engine, String type) {
+- X509KeyManager manager = provider.keyManager();
+- if (manager instanceof X509ExtendedKeyManager) {
+- return ((X509ExtendedKeyManager) manager).chooseEngineServerAlias(type, null, engine);
- }
+- return manager.chooseServerAlias(type, null, null);
- }
+-}
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialProvider.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialProvider.java
+deleted file mode 100644
+index f931fcfdbb..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialProvider.java
++++ /dev/null
+@@ -1,154 +0,0 @@
+-/*
+- * Copyright 2018 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- * http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-package io.netty.handler.ssl;
+-
+-import io.netty.buffer.ByteBufAllocator;
+-import io.netty.buffer.UnpooledByteBufAllocator;
+-import io.netty.internal.tcnative.SSL;
+-
+-import javax.net.ssl.SSLException;
+-import javax.net.ssl.X509KeyManager;
+-import java.security.PrivateKey;
+-import java.security.cert.X509Certificate;
+-
+-import static io.netty.handler.ssl.ReferenceCountedOpenSslContext.toBIO;
+-
+-/**
+- * Provides {@link OpenSslKeyMaterial} for a given alias.
+- */
+-class OpenSslKeyMaterialProvider {
+-
+- private final X509KeyManager keyManager;
+- private final String password;
+-
+- OpenSslKeyMaterialProvider(X509KeyManager keyManager, String password) {
+- this.keyManager = keyManager;
+- this.password = password;
+- }
+-
+- static void validateKeyMaterialSupported(X509Certificate[] keyCertChain, PrivateKey key, String keyPassword)
+- throws SSLException {
+- validateSupported(keyCertChain);
+- validateSupported(key, keyPassword);
+- }
+-
+- private static void validateSupported(PrivateKey key, String password) throws SSLException {
+- if (key == null) {
+- return;
+- }
+-
+- long pkeyBio = 0;
+- long pkey = 0;
-
-- /**
-- * Returns the number of successfully established SSL/TLS sessions in server mode.
-- */
-- public long acceptGood() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
- try {
-- return SSLContext.sessionAcceptGood(context.ctx);
+- pkeyBio = toBIO(UnpooledByteBufAllocator.DEFAULT, key);
+- pkey = SSL.parsePrivateKey(pkeyBio, password);
+- } catch (Exception e) {
+- throw new SSLException("PrivateKey type not supported " + key.getFormat(), e);
- } finally {
-- readerLock.unlock();
+- SSL.freeBIO(pkeyBio);
+- if (pkey != 0) {
+- SSL.freePrivateKey(pkey);
+- }
- }
- }
-
-- /**
-- * Returns the number of start renegotiations in server mode.
-- */
-- public long acceptRenegotiate() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
+- private static void validateSupported(X509Certificate[] certificates) throws SSLException {
+- if (certificates == null || certificates.length == 0) {
+- return;
+- }
+-
+- long chainBio = 0;
+- long chain = 0;
+- PemEncoded encoded = null;
- try {
-- return SSLContext.sessionAcceptRenegotiate(context.ctx);
+- encoded = PemX509Certificate.toPEM(UnpooledByteBufAllocator.DEFAULT, true, certificates);
+- chainBio = toBIO(UnpooledByteBufAllocator.DEFAULT, encoded.retain());
+- chain = SSL.parseX509Chain(chainBio);
+- } catch (Exception e) {
+- throw new SSLException("Certificate type not supported", e);
- } finally {
-- readerLock.unlock();
+- SSL.freeBIO(chainBio);
+- if (chain != 0) {
+- SSL.freeX509Chain(chain);
+- }
+- if (encoded != null) {
+- encoded.release();
+- }
- }
- }
-
- /**
-- * Returns the number of successfully reused sessions. In client mode, a session set with {@code SSL_set_session}
-- * successfully reused is counted as a hit. In server mode, a session successfully retrieved from internal or
-- * external cache is counted as a hit.
+- * Returns the underlying {@link X509KeyManager} that is used.
- */
-- public long hits() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
-- try {
-- return SSLContext.sessionHits(context.ctx);
-- } finally {
-- readerLock.unlock();
-- }
+- X509KeyManager keyManager() {
+- return keyManager;
- }
-
- /**
-- * Returns the number of successfully retrieved sessions from the external session cache in server mode.
+- * Returns the {@link OpenSslKeyMaterial} or {@code null} (if none) that should be used during the handshake by
+- * OpenSSL.
- */
-- public long cbHits() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
+- OpenSslKeyMaterial chooseKeyMaterial(ByteBufAllocator allocator, String alias) throws Exception {
+- X509Certificate[] certificates = keyManager.getCertificateChain(alias);
+- if (certificates == null || certificates.length == 0) {
+- return null;
+- }
+-
+- PrivateKey key = keyManager.getPrivateKey(alias);
+- PemEncoded encoded = PemX509Certificate.toPEM(allocator, true, certificates);
+- long chainBio = 0;
+- long pkeyBio = 0;
+- long chain = 0;
+- long pkey = 0;
- try {
-- return SSLContext.sessionCbHits(context.ctx);
+- chainBio = toBIO(allocator, encoded.retain());
+- chain = SSL.parseX509Chain(chainBio);
+-
+- OpenSslKeyMaterial keyMaterial;
+- if (key instanceof OpenSslPrivateKey) {
+- keyMaterial = ((OpenSslPrivateKey) key).newKeyMaterial(chain, certificates);
+- } else {
+- pkeyBio = toBIO(allocator, key);
+- pkey = key == null ? 0 : SSL.parsePrivateKey(pkeyBio, password);
+- keyMaterial = new DefaultOpenSslKeyMaterial(chain, pkey, certificates);
+- }
+-
+- // See the chain and pkey to 0 so we will not release it as the ownership was
+- // transferred to OpenSslKeyMaterial.
+- chain = 0;
+- pkey = 0;
+- return keyMaterial;
- } finally {
-- readerLock.unlock();
+- SSL.freeBIO(chainBio);
+- SSL.freeBIO(pkeyBio);
+- if (chain != 0) {
+- SSL.freeX509Chain(chain);
+- }
+- if (pkey != 0) {
+- SSL.freePrivateKey(pkey);
+- }
+- encoded.release();
- }
- }
-
- /**
-- * Returns the number of sessions proposed by clients that were not found in the internal session cache
-- * in server mode.
+- * Will be invoked once the provider should be destroyed.
- */
-- public long misses() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
-- try {
-- return SSLContext.sessionMisses(context.ctx);
-- } finally {
-- readerLock.unlock();
-- }
+- void destroy() {
+- // NOOP.
- }
+-}
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslPrivateKey.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslPrivateKey.java
+deleted file mode 100644
+index c2e4f108b7..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslPrivateKey.java
++++ /dev/null
+@@ -1,191 +0,0 @@
+-/*
+- * Copyright 2018 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- * http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-package io.netty.handler.ssl;
-
-- /**
-- * Returns the number of sessions proposed by clients and either found in the internal or external session cache
-- * in server mode, but that were invalid due to timeout. These sessions are not included in the {@link #hits()}
-- * count.
-- */
-- public long timeouts() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
-- try {
-- return SSLContext.sessionTimeouts(context.ctx);
-- } finally {
-- readerLock.unlock();
-- }
+-import io.netty.internal.tcnative.SSL;
+-import io.netty.util.AbstractReferenceCounted;
+-import io.netty.util.IllegalReferenceCountException;
+-import io.netty.util.internal.EmptyArrays;
+-
+-import javax.security.auth.Destroyable;
+-import java.security.PrivateKey;
+-import java.security.cert.X509Certificate;
+-
+-final class OpenSslPrivateKey extends AbstractReferenceCounted implements PrivateKey {
+-
+- private long privateKeyAddress;
+-
+- OpenSslPrivateKey(long privateKeyAddress) {
+- this.privateKeyAddress = privateKeyAddress;
- }
-
-- /**
-- * Returns the number of sessions that were removed because the maximum session cache size was exceeded.
-- */
-- public long cacheFull() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
-- try {
-- return SSLContext.sessionCacheFull(context.ctx);
-- } finally {
-- readerLock.unlock();
-- }
+- @Override
+- public String getAlgorithm() {
+- return "unknown";
- }
-
-- /**
-- * Returns the number of times a client presented a ticket that did not match any key in the list.
-- */
-- public long ticketKeyFail() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
-- try {
-- return SSLContext.sessionTicketKeyFail(context.ctx);
-- } finally {
-- readerLock.unlock();
+- @Override
+- public String getFormat() {
+- // As we do not support encoding we should return null as stated in the javadocs of PrivateKey.
+- return null;
+- }
+-
+- @Override
+- public byte[] getEncoded() {
+- return null;
+- }
+-
+- private long privateKeyAddress() {
+- if (refCnt() <= 0) {
+- throw new IllegalReferenceCountException();
- }
+- return privateKeyAddress;
+- }
+-
+- @Override
+- protected void deallocate() {
+- SSL.freePrivateKey(privateKeyAddress);
+- privateKeyAddress = 0;
+- }
+-
+- @Override
+- public OpenSslPrivateKey retain() {
+- super.retain();
+- return this;
+- }
+-
+- @Override
+- public OpenSslPrivateKey retain(int increment) {
+- super.retain(increment);
+- return this;
+- }
+-
+- @Override
+- public OpenSslPrivateKey touch() {
+- super.touch();
+- return this;
+- }
+-
+- @Override
+- public OpenSslPrivateKey touch(Object hint) {
+- return this;
- }
-
- /**
-- * Returns the number of times a client did not present a ticket and we issued a new one
+- * NOTE: This is a JDK8 interface/method. Due to backwards compatibility
+- * reasons it's not possible to slap the {@code @Override} annotation onto
+- * this method.
+- *
+- * @see Destroyable#destroy()
- */
-- public long ticketKeyNew() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
-- try {
-- return SSLContext.sessionTicketKeyNew(context.ctx);
-- } finally {
-- readerLock.unlock();
-- }
+- @Override
+- public void destroy() {
+- release(refCnt());
- }
-
- /**
-- * Returns the number of times a client presented a ticket derived from an older key,
-- * and we upgraded to the primary key.
+- * NOTE: This is a JDK8 interface/method. Due to backwards compatibility
+- * reasons it's not possible to slap the {@code @Override} annotation onto
+- * this method.
+- *
+- * @see Destroyable#isDestroyed()
- */
-- public long ticketKeyRenew() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
-- try {
-- return SSLContext.sessionTicketKeyRenew(context.ctx);
-- } finally {
-- readerLock.unlock();
-- }
+- @Override
+- public boolean isDestroyed() {
+- return refCnt() == 0;
- }
-
- /**
-- * Returns the number of times a client presented a ticket derived from the primary key.
+- * Create a new {@link OpenSslKeyMaterial} which uses the private key that is held by {@link OpenSslPrivateKey}.
+- *
+- * When the material is created we increment the reference count of the enclosing {@link OpenSslPrivateKey} and
+- * decrement it again when the reference count of the {@link OpenSslKeyMaterial} reaches {@code 0}.
- */
-- public long ticketKeyResume() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
-- try {
-- return SSLContext.sessionTicketKeyResume(context.ctx);
-- } finally {
-- readerLock.unlock();
+- OpenSslKeyMaterial newKeyMaterial(long certificateChain, X509Certificate[] chain) {
+- return new OpenSslPrivateKeyMaterial(certificateChain, chain);
+- }
+-
+- // Package-private for unit-test only
+- final class OpenSslPrivateKeyMaterial extends AbstractReferenceCounted implements OpenSslKeyMaterial {
+-
+- // Package-private for unit-test only
+- long certificateChain;
+- private final X509Certificate[] x509CertificateChain;
+-
+- OpenSslPrivateKeyMaterial(long certificateChain, X509Certificate[] x509CertificateChain) {
+- this.certificateChain = certificateChain;
+- this.x509CertificateChain = x509CertificateChain == null ?
+- EmptyArrays.EMPTY_X509_CERTIFICATES : x509CertificateChain;
+- OpenSslPrivateKey.this.retain();
+- }
+-
+- @Override
+- public X509Certificate[] certificateChain() {
+- return x509CertificateChain.clone();
+- }
+-
+- @Override
+- public long certificateChainAddress() {
+- if (refCnt() <= 0) {
+- throw new IllegalReferenceCountException();
+- }
+- return certificateChain;
+- }
+-
+- @Override
+- public long privateKeyAddress() {
+- if (refCnt() <= 0) {
+- throw new IllegalReferenceCountException();
+- }
+- return OpenSslPrivateKey.this.privateKeyAddress();
+- }
+-
+- @Override
+- public OpenSslKeyMaterial touch(Object hint) {
+- OpenSslPrivateKey.this.touch(hint);
+- return this;
+- }
+-
+- @Override
+- public OpenSslKeyMaterial retain() {
+- super.retain();
+- return this;
+- }
+-
+- @Override
+- public OpenSslKeyMaterial retain(int increment) {
+- super.retain(increment);
+- return this;
+- }
+-
+- @Override
+- public OpenSslKeyMaterial touch() {
+- OpenSslPrivateKey.this.touch();
+- return this;
+- }
+-
+- @Override
+- protected void deallocate() {
+- releaseChain();
+- OpenSslPrivateKey.this.release();
+- }
+-
+- private void releaseChain() {
+- SSL.freeX509Chain(certificateChain);
+- certificateChain = 0;
- }
- }
-}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionTicketKey.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionTicketKey.java
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslPrivateKeyMethod.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslPrivateKeyMethod.java
deleted file mode 100644
-index 79f71a6..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionTicketKey.java
+index d9fc877269..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslPrivateKeyMethod.java
+++ /dev/null
-@@ -1,78 +0,0 @@
+@@ -1,62 +0,0 @@
-/*
-- * Copyright 2015 The Netty Project
+- * Copyright 2019 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
@@ -2224,75 +2469,59 @@ index 79f71a6..0000000
- */
-package io.netty.handler.ssl;
-
--import io.netty.internal.tcnative.SessionTicketKey;
+-import io.netty.internal.tcnative.SSLPrivateKeyMethod;
+-import io.netty.util.internal.UnstableApi;
+-
+-import javax.net.ssl.SSLEngine;
-
-/**
-- * Session Ticket Key
+- * Allow to customize private key signing / decrypting (when using RSA). Only supported when using BoringSSL atm.
- */
--public final class OpenSslSessionTicketKey {
--
-- /**
-- * Size of session ticket key name
-- */
-- public static final int NAME_SIZE = SessionTicketKey.NAME_SIZE;
-- /**
-- * Size of session ticket key HMAC key
-- */
-- public static final int HMAC_KEY_SIZE = SessionTicketKey.HMAC_KEY_SIZE;
-- /**
-- * Size of session ticket key AES key
-- */
-- public static final int AES_KEY_SIZE = SessionTicketKey.AES_KEY_SIZE;
-- /**
-- * Size of session ticker key
-- */
-- public static final int TICKET_KEY_SIZE = SessionTicketKey.TICKET_KEY_SIZE;
--
-- final SessionTicketKey key;
+-@UnstableApi
+-public interface OpenSslPrivateKeyMethod {
+- int SSL_SIGN_RSA_PKCS1_SHA1 = SSLPrivateKeyMethod.SSL_SIGN_RSA_PKCS1_SHA1;
+- int SSL_SIGN_RSA_PKCS1_SHA256 = SSLPrivateKeyMethod.SSL_SIGN_RSA_PKCS1_SHA256;
+- int SSL_SIGN_RSA_PKCS1_SHA384 = SSLPrivateKeyMethod.SSL_SIGN_RSA_PKCS1_SHA384;
+- int SSL_SIGN_RSA_PKCS1_SHA512 = SSLPrivateKeyMethod.SSL_SIGN_RSA_PKCS1_SHA512;
+- int SSL_SIGN_ECDSA_SHA1 = SSLPrivateKeyMethod.SSL_SIGN_ECDSA_SHA1;
+- int SSL_SIGN_ECDSA_SECP256R1_SHA256 = SSLPrivateKeyMethod.SSL_SIGN_ECDSA_SECP256R1_SHA256;
+- int SSL_SIGN_ECDSA_SECP384R1_SHA384 = SSLPrivateKeyMethod.SSL_SIGN_ECDSA_SECP384R1_SHA384;
+- int SSL_SIGN_ECDSA_SECP521R1_SHA512 = SSLPrivateKeyMethod.SSL_SIGN_ECDSA_SECP521R1_SHA512;
+- int SSL_SIGN_RSA_PSS_RSAE_SHA256 = SSLPrivateKeyMethod.SSL_SIGN_RSA_PSS_RSAE_SHA256;
+- int SSL_SIGN_RSA_PSS_RSAE_SHA384 = SSLPrivateKeyMethod.SSL_SIGN_RSA_PSS_RSAE_SHA384;
+- int SSL_SIGN_RSA_PSS_RSAE_SHA512 = SSLPrivateKeyMethod.SSL_SIGN_RSA_PSS_RSAE_SHA512;
+- int SSL_SIGN_ED25519 = SSLPrivateKeyMethod.SSL_SIGN_ED25519;
+- int SSL_SIGN_RSA_PKCS1_MD5_SHA1 = SSLPrivateKeyMethod.SSL_SIGN_RSA_PKCS1_MD5_SHA1;
-
- /**
-- * Construct a OpenSslSessionTicketKey.
+- * Signs the input with the given key and returns the signed bytes.
- *
-- * @param name the name of the session ticket key
-- * @param hmacKey the HMAC key of the session ticket key
-- * @param aesKey the AES key of the session ticket key
+- * @param engine the {@link SSLEngine}
+- * @param signatureAlgorithm the algorithm to use for signing
+- * @param input the digest itself
+- * @return the signed data (must not be {@code null})
+- * @throws Exception thrown if an error is encountered during the signing
- */
-- public OpenSslSessionTicketKey(byte[] name, byte[] hmacKey, byte[] aesKey) {
-- key = new SessionTicketKey(name.clone(), hmacKey.clone(), aesKey.clone());
-- }
--
-- /**
-- * Get name.
-- * @return the name of the session ticket key
-- */
-- public byte[] name() {
-- return key.getName().clone();
-- }
--
-- /**
-- * Get HMAC key.
-- * @return the HMAC key of the session ticket key
-- */
-- public byte[] hmacKey() {
-- return key.getHmacKey().clone();
-- }
+- byte[] sign(SSLEngine engine, int signatureAlgorithm, byte[] input) throws Exception;
-
- /**
-- * Get AES Key.
-- * @return the AES key of the session ticket key
+- * Decrypts the input with the given key and returns the decrypted bytes.
+- *
+- * @param engine the {@link SSLEngine}
+- * @param input the input which should be decrypted
+- * @return the decrypted data (must not be {@code null})
+- * @throws Exception thrown if an error is encountered during the decrypting
- */
-- public byte[] aesKey() {
-- return key.getAesKey().clone();
-- }
+- byte[] decrypt(SSLEngine engine, byte[] input) throws Exception;
-}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslClientContext.java b/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslClientContext.java
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerContext.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslServerContext.java
deleted file mode 100644
-index b213573..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslClientContext.java
+index da342de0f2..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerContext.java
+++ /dev/null
-@@ -1,298 +0,0 @@
+@@ -1,367 +0,0 @@
-/*
-- * Copyright 2016 The Netty Project
+- * Copyright 2014 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
@@ -2308,295 +2537,364 @@ index b213573..0000000
- */
-package io.netty.handler.ssl;
-
--import io.netty.util.internal.logging.InternalLogger;
--import io.netty.util.internal.logging.InternalLoggerFactory;
--import io.netty.internal.tcnative.CertificateRequestedCallback;
-import io.netty.internal.tcnative.SSL;
--import io.netty.internal.tcnative.SSLContext;
-
+-import java.io.File;
-import java.security.KeyStore;
-import java.security.PrivateKey;
-import java.security.cert.X509Certificate;
--import java.util.HashSet;
--import java.util.Set;
-
+-import javax.net.ssl.KeyManager;
-import javax.net.ssl.KeyManagerFactory;
-import javax.net.ssl.SSLException;
--import javax.net.ssl.SSLHandshakeException;
+-import javax.net.ssl.TrustManager;
-import javax.net.ssl.TrustManagerFactory;
--import javax.net.ssl.X509ExtendedKeyManager;
--import javax.net.ssl.X509ExtendedTrustManager;
--import javax.net.ssl.X509KeyManager;
--import javax.net.ssl.X509TrustManager;
--import javax.security.auth.x500.X500Principal;
+-
+-import static io.netty.handler.ssl.ReferenceCountedOpenSslServerContext.newSessionContext;
-
-/**
-- * A client-side {@link SslContext} which uses OpenSSL's SSL/TLS implementation.
-- * <p>Instances of this class must be {@link #release() released} or else native memory will leak!
-- *
-- * <p>Instances of this class <strong>must not</strong> be released before any {@link ReferenceCountedOpenSslEngine}
-- * which depends upon the instance of this class is released. Otherwise if any method of
-- * {@link ReferenceCountedOpenSslEngine} is called which uses this class's JNI resources the JVM may crash.
+- * A server-side {@link SslContext} which uses OpenSSL's SSL/TLS implementation.
+- * <p>This class will use a finalizer to ensure native resources are automatically cleaned up. To avoid finalizers
+- * and manually release the native memory see {@link ReferenceCountedOpenSslServerContext}.
- */
--public final class ReferenceCountedOpenSslClientContext extends ReferenceCountedOpenSslContext {
-- private static final InternalLogger logger =
-- InternalLoggerFactory.getInstance(ReferenceCountedOpenSslClientContext.class);
-- private final OpenSslSessionContext sessionContext;
+-public final class OpenSslServerContext extends OpenSslContext {
+- private final OpenSslServerSessionContext sessionContext;
-
-- ReferenceCountedOpenSslClientContext(X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory,
-- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword,
-- KeyManagerFactory keyManagerFactory, Iterable<String> ciphers,
-- CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
-- String[] protocols, long sessionCacheSize, long sessionTimeout,
-- boolean enableOcsp) throws SSLException {
-- super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, SSL.SSL_MODE_CLIENT, keyCertChain,
-- ClientAuth.NONE, protocols, false, enableOcsp, true);
-- boolean success = false;
-- try {
-- sessionContext = newSessionContext(this, ctx, engineMap, trustCertCollection, trustManagerFactory,
-- keyCertChain, key, keyPassword, keyManagerFactory);
-- success = true;
-- } finally {
-- if (!success) {
-- release();
-- }
-- }
+- /**
+- * Creates a new instance.
+- *
+- * @param certChainFile an X.509 certificate chain file in PEM format
+- * @param keyFile a PKCS#8 private key file in PEM format
+- * @deprecated use {@link SslContextBuilder}
+- */
+- @Deprecated
+- public OpenSslServerContext(File certChainFile, File keyFile) throws SSLException {
+- this(certChainFile, keyFile, null);
- }
-
-- @Override
-- OpenSslKeyMaterialManager keyMaterialManager() {
-- return null;
+- /**
+- * Creates a new instance.
+- *
+- * @param certChainFile an X.509 certificate chain file in PEM format
+- * @param keyFile a PKCS#8 private key file in PEM format
+- * @param keyPassword the password of the {@code keyFile}.
+- * {@code null} if it's not password-protected.
+- * @deprecated use {@link SslContextBuilder}
+- */
+- @Deprecated
+- public OpenSslServerContext(File certChainFile, File keyFile, String keyPassword) throws SSLException {
+- this(certChainFile, keyFile, keyPassword, null, IdentityCipherSuiteFilter.INSTANCE,
+- ApplicationProtocolConfig.DISABLED, 0, 0);
- }
-
-- @Override
-- public OpenSslSessionContext sessionContext() {
-- return sessionContext;
+- /**
+- * Creates a new instance.
+- *
+- * @param certChainFile an X.509 certificate chain file in PEM format
+- * @param keyFile a PKCS#8 private key file in PEM format
+- * @param keyPassword the password of the {@code keyFile}.
+- * {@code null} if it's not password-protected.
+- * @param ciphers the cipher suites to enable, in the order of preference.
+- * {@code null} to use the default cipher suites.
+- * @param apn Provides a means to configure parameters related to application protocol negotiation.
+- * @param sessionCacheSize the size of the cache used for storing SSL session objects.
+- * {@code 0} to use the default value.
+- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
+- * {@code 0} to use the default value.
+- * @deprecated use {@link SslContextBuilder}
+- */
+- @Deprecated
+- public OpenSslServerContext(
+- File certChainFile, File keyFile, String keyPassword,
+- Iterable<String> ciphers, ApplicationProtocolConfig apn,
+- long sessionCacheSize, long sessionTimeout) throws SSLException {
+- this(certChainFile, keyFile, keyPassword, ciphers, IdentityCipherSuiteFilter.INSTANCE,
+- apn, sessionCacheSize, sessionTimeout);
- }
-
-- static OpenSslSessionContext newSessionContext(ReferenceCountedOpenSslContext thiz, long ctx,
-- OpenSslEngineMap engineMap,
-- X509Certificate[] trustCertCollection,
-- TrustManagerFactory trustManagerFactory,
-- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword,
-- KeyManagerFactory keyManagerFactory) throws SSLException {
-- if (key == null && keyCertChain != null || key != null && keyCertChain == null) {
-- throw new IllegalArgumentException(
-- "Either both keyCertChain and key needs to be null or none of them");
-- }
-- try {
-- if (!OpenSsl.useKeyManagerFactory()) {
-- if (keyManagerFactory != null) {
-- throw new IllegalArgumentException(
-- "KeyManagerFactory not supported");
-- }
-- if (keyCertChain != null/* && key != null*/) {
-- setKeyMaterial(ctx, keyCertChain, key, keyPassword);
-- }
-- } else {
-- // javadocs state that keyManagerFactory has precedent over keyCertChain
-- if (keyManagerFactory == null && keyCertChain != null) {
-- keyManagerFactory = buildKeyManagerFactory(
-- keyCertChain, key, keyPassword, keyManagerFactory);
-- }
--
-- if (keyManagerFactory != null) {
-- X509KeyManager keyManager = chooseX509KeyManager(keyManagerFactory.getKeyManagers());
-- OpenSslKeyMaterialManager materialManager = useExtendedKeyManager(keyManager) ?
-- new OpenSslExtendedKeyMaterialManager(
-- (X509ExtendedKeyManager) keyManager, keyPassword) :
-- new OpenSslKeyMaterialManager(keyManager, keyPassword);
-- SSLContext.setCertRequestedCallback(ctx, new OpenSslCertificateRequestedCallback(
-- engineMap, materialManager));
-- }
-- }
-- } catch (Exception e) {
-- throw new SSLException("failed to set certificate and key", e);
-- }
--
-- SSLContext.setVerify(ctx, SSL.SSL_CVERIFY_NONE, VERIFY_DEPTH);
--
-- try {
-- if (trustCertCollection != null) {
-- trustManagerFactory = buildTrustManagerFactory(trustCertCollection, trustManagerFactory);
-- } else if (trustManagerFactory == null) {
-- trustManagerFactory = TrustManagerFactory.getInstance(
-- TrustManagerFactory.getDefaultAlgorithm());
-- trustManagerFactory.init((KeyStore) null);
-- }
-- final X509TrustManager manager = chooseTrustManager(trustManagerFactory.getTrustManagers());
--
-- // IMPORTANT: The callbacks set for verification must be static to prevent memory leak as
-- // otherwise the context can never be collected. This is because the JNI code holds
-- // a global reference to the callbacks.
-- //
-- // See https://github.com/netty/netty/issues/5372
--
-- // Use this to prevent an error when running on java < 7
-- if (useExtendedTrustManager(manager)) {
-- SSLContext.setCertVerifyCallback(ctx,
-- new ExtendedTrustManagerVerifyCallback(engineMap, (X509ExtendedTrustManager) manager));
-- } else {
-- SSLContext.setCertVerifyCallback(ctx, new TrustManagerVerifyCallback(engineMap, manager));
-- }
-- } catch (Exception e) {
-- throw new SSLException("unable to setup trustmanager", e);
-- }
-- return new OpenSslClientSessionContext(thiz);
+- /**
+- * Creates a new instance.
+- *
+- * @param certChainFile an X.509 certificate chain file in PEM format
+- * @param keyFile a PKCS#8 private key file in PEM format
+- * @param keyPassword the password of the {@code keyFile}.
+- * {@code null} if it's not password-protected.
+- * @param ciphers the cipher suites to enable, in the order of preference.
+- * {@code null} to use the default cipher suites.
+- * @param nextProtocols the application layer protocols to accept, in the order of preference.
+- * {@code null} to disable TLS NPN/ALPN extension.
+- * @param sessionCacheSize the size of the cache used for storing SSL session objects.
+- * {@code 0} to use the default value.
+- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
+- * {@code 0} to use the default value.
+- * @deprecated use {@link SslContextBuilder}
+- */
+- @Deprecated
+- public OpenSslServerContext(
+- File certChainFile, File keyFile, String keyPassword,
+- Iterable<String> ciphers, Iterable<String> nextProtocols,
+- long sessionCacheSize, long sessionTimeout) throws SSLException {
+- this(certChainFile, keyFile, keyPassword, ciphers,
+- toApplicationProtocolConfig(nextProtocols), sessionCacheSize, sessionTimeout);
- }
-
-- // No cache is currently supported for client side mode.
-- static final class OpenSslClientSessionContext extends OpenSslSessionContext {
-- OpenSslClientSessionContext(ReferenceCountedOpenSslContext context) {
-- super(context);
-- }
--
-- @Override
-- public void setSessionTimeout(int seconds) {
-- if (seconds < 0) {
-- throw new IllegalArgumentException();
-- }
-- }
--
-- @Override
-- public int getSessionTimeout() {
-- return 0;
-- }
--
-- @Override
-- public void setSessionCacheSize(int size) {
-- if (size < 0) {
-- throw new IllegalArgumentException();
-- }
-- }
--
-- @Override
-- public int getSessionCacheSize() {
-- return 0;
-- }
--
-- @Override
-- public void setSessionCacheEnabled(boolean enabled) {
-- // ignored
-- }
--
-- @Override
-- public boolean isSessionCacheEnabled() {
-- return false;
-- }
+- /**
+- * Creates a new instance.
+- *
+- * @param certChainFile an X.509 certificate chain file in PEM format
+- * @param keyFile a PKCS#8 private key file in PEM format
+- * @param keyPassword the password of the {@code keyFile}.
+- * {@code null} if it's not password-protected.
+- * @param ciphers the cipher suites to enable, in the order of preference.
+- * {@code null} to use the default cipher suites.
+- * @param config Application protocol config.
+- * @param sessionCacheSize the size of the cache used for storing SSL session objects.
+- * {@code 0} to use the default value.
+- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
+- * {@code 0} to use the default value.
+- * @deprecated use {@link SslContextBuilder}
+- */
+- @Deprecated
+- public OpenSslServerContext(
+- File certChainFile, File keyFile, String keyPassword, TrustManagerFactory trustManagerFactory,
+- Iterable<String> ciphers, ApplicationProtocolConfig config,
+- long sessionCacheSize, long sessionTimeout) throws SSLException {
+- this(certChainFile, keyFile, keyPassword, trustManagerFactory, ciphers,
+- toNegotiator(config), sessionCacheSize, sessionTimeout);
- }
-
-- private static final class TrustManagerVerifyCallback extends AbstractCertificateVerifier {
-- private final X509TrustManager manager;
--
-- TrustManagerVerifyCallback(OpenSslEngineMap engineMap, X509TrustManager manager) {
-- super(engineMap);
-- this.manager = manager;
-- }
+- /**
+- * Creates a new instance.
+- *
+- * @param certChainFile an X.509 certificate chain file in PEM format
+- * @param keyFile a PKCS#8 private key file in PEM format
+- * @param keyPassword the password of the {@code keyFile}.
+- * {@code null} if it's not password-protected.
+- * @param ciphers the cipher suites to enable, in the order of preference.
+- * {@code null} to use the default cipher suites.
+- * @param apn Application protocol negotiator.
+- * @param sessionCacheSize the size of the cache used for storing SSL session objects.
+- * {@code 0} to use the default value.
+- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
+- * {@code 0} to use the default value.
+- * @deprecated use {@link SslContextBuilder}
+- */
+- @Deprecated
+- public OpenSslServerContext(
+- File certChainFile, File keyFile, String keyPassword, TrustManagerFactory trustManagerFactory,
+- Iterable<String> ciphers, OpenSslApplicationProtocolNegotiator apn,
+- long sessionCacheSize, long sessionTimeout) throws SSLException {
+- this(null, trustManagerFactory, certChainFile, keyFile, keyPassword, null,
+- ciphers, null, apn, sessionCacheSize, sessionTimeout);
+- }
-
-- @Override
-- void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts, String auth)
-- throws Exception {
-- manager.checkServerTrusted(peerCerts, auth);
-- }
+- /**
+- * Creates a new instance.
+- *
+- * @param certChainFile an X.509 certificate chain file in PEM format
+- * @param keyFile a PKCS#8 private key file in PEM format
+- * @param keyPassword the password of the {@code keyFile}.
+- * {@code null} if it's not password-protected.
+- * @param ciphers the cipher suites to enable, in the order of preference.
+- * {@code null} to use the default cipher suites.
+- * @param cipherFilter a filter to apply over the supplied list of ciphers
+- * @param apn Provides a means to configure parameters related to application protocol negotiation.
+- * @param sessionCacheSize the size of the cache used for storing SSL session objects.
+- * {@code 0} to use the default value.
+- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
+- * {@code 0} to use the default value.
+- * @deprecated use {@link SslContextBuilder}
+- */
+- @Deprecated
+- public OpenSslServerContext(
+- File certChainFile, File keyFile, String keyPassword,
+- Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
+- long sessionCacheSize, long sessionTimeout) throws SSLException {
+- this(null, null, certChainFile, keyFile, keyPassword, null,
+- ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout);
- }
-
-- private static final class ExtendedTrustManagerVerifyCallback extends AbstractCertificateVerifier {
-- private final X509ExtendedTrustManager manager;
+- /**
+- * Creates a new instance.
+- *
+- * @param trustCertCollectionFile an X.509 certificate collection file in PEM format.
+- * This provides the certificate collection used for mutual authentication.
+- * {@code null} to use the system default
+- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
+- * that verifies the certificates sent from clients.
+- * {@code null} to use the default or the results of parsing
+- * {@code trustCertCollectionFile}.
+- * @param keyCertChainFile an X.509 certificate chain file in PEM format
+- * @param keyFile a PKCS#8 private key file in PEM format
+- * @param keyPassword the password of the {@code keyFile}.
+- * {@code null} if it's not password-protected.
+- * @param keyManagerFactory the {@link KeyManagerFactory} that provides the {@link KeyManager}s
+- * that is used to encrypt data being sent to clients.
+- * {@code null} to use the default or the results of parsing
+- * {@code keyCertChainFile} and {@code keyFile}.
+- * @param ciphers the cipher suites to enable, in the order of preference.
+- * {@code null} to use the default cipher suites.
+- * @param cipherFilter a filter to apply over the supplied list of ciphers
+- * Only required if {@code provider} is {@link SslProvider#JDK}
+- * @param config Provides a means to configure parameters related to application protocol negotiation.
+- * @param sessionCacheSize the size of the cache used for storing SSL session objects.
+- * {@code 0} to use the default value.
+- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
+- * {@code 0} to use the default value.
+- * @deprecated use {@link SslContextBuilder}
+- */
+- @Deprecated
+- public OpenSslServerContext(
+- File trustCertCollectionFile, TrustManagerFactory trustManagerFactory,
+- File keyCertChainFile, File keyFile, String keyPassword, KeyManagerFactory keyManagerFactory,
+- Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig config,
+- long sessionCacheSize, long sessionTimeout) throws SSLException {
+- this(trustCertCollectionFile, trustManagerFactory, keyCertChainFile, keyFile, keyPassword, keyManagerFactory,
+- ciphers, cipherFilter, toNegotiator(config), sessionCacheSize, sessionTimeout);
+- }
-
-- ExtendedTrustManagerVerifyCallback(OpenSslEngineMap engineMap, X509ExtendedTrustManager manager) {
-- super(engineMap);
-- this.manager = manager;
-- }
+- /**
+- * Creates a new instance.
+- *
+- * @param certChainFile an X.509 certificate chain file in PEM format
+- * @param keyFile a PKCS#8 private key file in PEM format
+- * @param keyPassword the password of the {@code keyFile}.
+- * {@code null} if it's not password-protected.
+- * @param ciphers the cipher suites to enable, in the order of preference.
+- * {@code null} to use the default cipher suites.
+- * @param cipherFilter a filter to apply over the supplied list of ciphers
+- * @param config Application protocol config.
+- * @param sessionCacheSize the size of the cache used for storing SSL session objects.
+- * {@code 0} to use the default value.
+- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
+- * {@code 0} to use the default value.
+- * @deprecated use {@link SslContextBuilder}
+- */
+- @Deprecated
+- public OpenSslServerContext(File certChainFile, File keyFile, String keyPassword,
+- TrustManagerFactory trustManagerFactory, Iterable<String> ciphers,
+- CipherSuiteFilter cipherFilter, ApplicationProtocolConfig config,
+- long sessionCacheSize, long sessionTimeout) throws SSLException {
+- this(null, trustManagerFactory, certChainFile, keyFile, keyPassword, null, ciphers, cipherFilter,
+- toNegotiator(config), sessionCacheSize, sessionTimeout);
+- }
-
-- @Override
-- void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts, String auth)
-- throws Exception {
-- manager.checkServerTrusted(peerCerts, auth, engine);
-- }
+- /**
+- * Creates a new instance.
+- *
+- * @param certChainFile an X.509 certificate chain file in PEM format
+- * @param keyFile a PKCS#8 private key file in PEM format
+- * @param keyPassword the password of the {@code keyFile}.
+- * {@code null} if it's not password-protected.
+- * @param ciphers the cipher suites to enable, in the order of preference.
+- * {@code null} to use the default cipher suites.
+- * @param cipherFilter a filter to apply over the supplied list of ciphers
+- * @param apn Application protocol negotiator.
+- * @param sessionCacheSize the size of the cache used for storing SSL session objects.
+- * {@code 0} to use the default value.
+- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
+- * {@code 0} to use the default value.
+- * @deprecated use {@link SslContextBuilder}}
+- */
+- @Deprecated
+- public OpenSslServerContext(
+- File certChainFile, File keyFile, String keyPassword, TrustManagerFactory trustManagerFactory,
+- Iterable<String> ciphers, CipherSuiteFilter cipherFilter, OpenSslApplicationProtocolNegotiator apn,
+- long sessionCacheSize, long sessionTimeout) throws SSLException {
+- this(null, trustManagerFactory, certChainFile, keyFile, keyPassword, null, ciphers, cipherFilter,
+- apn, sessionCacheSize, sessionTimeout);
- }
-
-- private static final class OpenSslCertificateRequestedCallback implements CertificateRequestedCallback {
-- private final OpenSslEngineMap engineMap;
-- private final OpenSslKeyMaterialManager keyManagerHolder;
+- /**
+- * Creates a new instance.
+- *
+- *
+- * @param trustCertCollectionFile an X.509 certificate collection file in PEM format.
+- * This provides the certificate collection used for mutual authentication.
+- * {@code null} to use the system default
+- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
+- * that verifies the certificates sent from clients.
+- * {@code null} to use the default or the results of parsing
+- * {@code trustCertCollectionFile}.
+- * @param keyCertChainFile an X.509 certificate chain file in PEM format
+- * @param keyFile a PKCS#8 private key file in PEM format
+- * @param keyPassword the password of the {@code keyFile}.
+- * {@code null} if it's not password-protected.
+- * @param keyManagerFactory the {@link KeyManagerFactory} that provides the {@link KeyManager}s
+- * that is used to encrypt data being sent to clients.
+- * {@code null} to use the default or the results of parsing
+- * {@code keyCertChainFile} and {@code keyFile}.
+- * @param ciphers the cipher suites to enable, in the order of preference.
+- * {@code null} to use the default cipher suites.
+- * @param cipherFilter a filter to apply over the supplied list of ciphers
+- * Only required if {@code provider} is {@link SslProvider#JDK}
+- * @param apn Application Protocol Negotiator object
+- * @param sessionCacheSize the size of the cache used for storing SSL session objects.
+- * {@code 0} to use the default value.
+- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
+- * {@code 0} to use the default value.
+- * @deprecated use {@link SslContextBuilder}
+- */
+- @Deprecated
+- public OpenSslServerContext(
+- File trustCertCollectionFile, TrustManagerFactory trustManagerFactory,
+- File keyCertChainFile, File keyFile, String keyPassword, KeyManagerFactory keyManagerFactory,
+- Iterable<String> ciphers, CipherSuiteFilter cipherFilter, OpenSslApplicationProtocolNegotiator apn,
+- long sessionCacheSize, long sessionTimeout) throws SSLException {
+- this(toX509CertificatesInternal(trustCertCollectionFile), trustManagerFactory,
+- toX509CertificatesInternal(keyCertChainFile), toPrivateKeyInternal(keyFile, keyPassword),
+- keyPassword, keyManagerFactory, ciphers, cipherFilter,
+- apn, sessionCacheSize, sessionTimeout, ClientAuth.NONE, null, false, false, KeyStore.getDefaultType());
+- }
-
-- OpenSslCertificateRequestedCallback(OpenSslEngineMap engineMap, OpenSslKeyMaterialManager keyManagerHolder) {
-- this.engineMap = engineMap;
-- this.keyManagerHolder = keyManagerHolder;
-- }
+- OpenSslServerContext(
+- X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory,
+- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory,
+- Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
+- long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[] protocols, boolean startTls,
+- boolean enableOcsp, String keyStore) throws SSLException {
+- this(trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory, ciphers,
+- cipherFilter, toNegotiator(apn), sessionCacheSize, sessionTimeout, clientAuth, protocols, startTls,
+- enableOcsp, keyStore);
+- }
-
-- @Override
-- public KeyMaterial requested(long ssl, byte[] keyTypeBytes, byte[][] asn1DerEncodedPrincipals) {
-- final ReferenceCountedOpenSslEngine engine = engineMap.get(ssl);
-- try {
-- final Set<String> keyTypesSet = supportedClientKeyTypes(keyTypeBytes);
-- final String[] keyTypes = keyTypesSet.toArray(new String[keyTypesSet.size()]);
-- final X500Principal[] issuers;
-- if (asn1DerEncodedPrincipals == null) {
-- issuers = null;
-- } else {
-- issuers = new X500Principal[asn1DerEncodedPrincipals.length];
-- for (int i = 0; i < asn1DerEncodedPrincipals.length; i++) {
-- issuers[i] = new X500Principal(asn1DerEncodedPrincipals[i]);
-- }
-- }
-- return keyManagerHolder.keyMaterial(engine, keyTypes, issuers);
-- } catch (Throwable cause) {
-- logger.debug("request of key failed", cause);
-- SSLHandshakeException e = new SSLHandshakeException("General OpenSslEngine problem");
-- e.initCause(cause);
-- engine.handshakeException = e;
-- return null;
-- }
-- }
+- @SuppressWarnings("deprecation")
+- private OpenSslServerContext(
+- X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory,
+- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory,
+- Iterable<String> ciphers, CipherSuiteFilter cipherFilter, OpenSslApplicationProtocolNegotiator apn,
+- long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[] protocols, boolean startTls,
+- boolean enableOcsp, String keyStore) throws SSLException {
+- super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, SSL.SSL_MODE_SERVER, keyCertChain,
+- clientAuth, protocols, startTls, enableOcsp);
-
-- /**
-- * Gets the supported key types for client certificates.
-- *
-- * @param clientCertificateTypes {@code ClientCertificateType} values provided by the server.
-- * See https://www.ietf.org/assignments/tls-parameters/tls-parameters.xml.
-- * @return supported key types that can be used in {@code X509KeyManager.chooseClientAlias} and
-- * {@code X509ExtendedKeyManager.chooseEngineClientAlias}.
-- */
-- private static Set<String> supportedClientKeyTypes(byte[] clientCertificateTypes) {
-- Set<String> result = new HashSet<String>(clientCertificateTypes.length);
-- for (byte keyTypeCode : clientCertificateTypes) {
-- String keyType = clientKeyType(keyTypeCode);
-- if (keyType == null) {
-- // Unsupported client key type -- ignore
-- continue;
-- }
-- result.add(keyType);
+- // Create a new SSL_CTX and configure it.
+- boolean success = false;
+- try {
+- OpenSslKeyMaterialProvider.validateKeyMaterialSupported(keyCertChain, key, keyPassword);
+- sessionContext = newSessionContext(this, ctx, engineMap, trustCertCollection, trustManagerFactory,
+- keyCertChain, key, keyPassword, keyManagerFactory, keyStore);
+- success = true;
+- } finally {
+- if (!success) {
+- release();
- }
-- return result;
- }
+- }
-
-- private static String clientKeyType(byte clientCertificateType) {
-- // See also http://www.ietf.org/assignments/tls-parameters/tls-parameters.xml
-- switch (clientCertificateType) {
-- case CertificateRequestedCallback.TLS_CT_RSA_SIGN:
-- return OpenSslKeyMaterialManager.KEY_TYPE_RSA; // RFC rsa_sign
-- case CertificateRequestedCallback.TLS_CT_RSA_FIXED_DH:
-- return OpenSslKeyMaterialManager.KEY_TYPE_DH_RSA; // RFC rsa_fixed_dh
-- case CertificateRequestedCallback.TLS_CT_ECDSA_SIGN:
-- return OpenSslKeyMaterialManager.KEY_TYPE_EC; // RFC ecdsa_sign
-- case CertificateRequestedCallback.TLS_CT_RSA_FIXED_ECDH:
-- return OpenSslKeyMaterialManager.KEY_TYPE_EC_RSA; // RFC rsa_fixed_ecdh
-- case CertificateRequestedCallback.TLS_CT_ECDSA_FIXED_ECDH:
-- return OpenSslKeyMaterialManager.KEY_TYPE_EC_EC; // RFC ecdsa_fixed_ecdh
-- default:
-- return null;
-- }
-- }
+- @Override
+- public OpenSslServerSessionContext sessionContext() {
+- return sessionContext;
- }
-}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslContext.java b/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslContext.java
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerSessionContext.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslServerSessionContext.java
deleted file mode 100644
-index ee049ab..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslContext.java
+index 691ee0b661..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerSessionContext.java
+++ /dev/null
-@@ -1,867 +0,0 @@
+@@ -1,124 +0,0 @@
-/*
-- * Copyright 2016 The Netty Project
+- * Copyright 2014 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
@@ -2612,864 +2910,874 @@ index ee049ab..0000000
- */
-package io.netty.handler.ssl;
-
--import io.netty.buffer.ByteBuf;
--import io.netty.buffer.ByteBufAllocator;
--import io.netty.internal.tcnative.CertificateVerifier;
-import io.netty.internal.tcnative.SSL;
-import io.netty.internal.tcnative.SSLContext;
--import io.netty.util.AbstractReferenceCounted;
--import io.netty.util.ReferenceCounted;
--import io.netty.util.ResourceLeakDetector;
--import io.netty.util.ResourceLeakDetectorFactory;
--import io.netty.util.ResourceLeakTracker;
--import io.netty.util.internal.PlatformDependent;
--import io.netty.util.internal.StringUtil;
--import io.netty.util.internal.SystemPropertyUtil;
--import io.netty.util.internal.logging.InternalLogger;
--import io.netty.util.internal.logging.InternalLoggerFactory;
--
--import java.security.AccessController;
--import java.security.PrivateKey;
--import java.security.PrivilegedAction;
--import java.security.cert.CertPathValidatorException;
--import java.security.cert.Certificate;
--import java.security.cert.CertificateExpiredException;
--import java.security.cert.CertificateNotYetValidException;
--import java.security.cert.CertificateRevokedException;
--import java.security.cert.X509Certificate;
--import java.util.ArrayList;
--import java.util.Arrays;
--import java.util.Collections;
--import java.util.List;
--import java.util.Map;
-
-import java.util.concurrent.locks.Lock;
--import java.util.concurrent.locks.ReadWriteLock;
--import java.util.concurrent.locks.ReentrantReadWriteLock;
--import javax.net.ssl.KeyManager;
--import javax.net.ssl.SSLEngine;
--import javax.net.ssl.SSLException;
--import javax.net.ssl.SSLHandshakeException;
--import javax.net.ssl.TrustManager;
--import javax.net.ssl.X509ExtendedKeyManager;
--import javax.net.ssl.X509ExtendedTrustManager;
--import javax.net.ssl.X509KeyManager;
--import javax.net.ssl.X509TrustManager;
-
--import static io.netty.util.internal.ObjectUtil.checkNotNull;
--import static io.netty.util.internal.ObjectUtil.checkPositiveOrZero;
-
-/**
-- * An implementation of {@link SslContext} which works with libraries that support the
-- * <a href="https://www.openssl.org/">OpenSsl</a> C library API.
-- * <p>Instances of this class must be {@link #release() released} or else native memory will leak!
-- *
-- * <p>Instances of this class <strong>must not</strong> be released before any {@link ReferenceCountedOpenSslEngine}
-- * which depends upon the instance of this class is released. Otherwise if any method of
-- * {@link ReferenceCountedOpenSslEngine} is called which uses this class's JNI resources the JVM may crash.
+- * {@link OpenSslSessionContext} implementation which offers extra methods which are only useful for the server-side.
- */
--public abstract class ReferenceCountedOpenSslContext extends SslContext implements ReferenceCounted {
-- private static final InternalLogger logger =
-- InternalLoggerFactory.getInstance(ReferenceCountedOpenSslContext.class);
-- /**
-- * To make it easier for users to replace JDK implementation with OpenSsl version we also use
-- * {@code jdk.tls.rejectClientInitiatedRenegotiation} to allow disabling client initiated renegotiation.
-- * Java8+ uses this system property as well.
-- * <p>
-- * See also <a href="http://blog.ivanristic.com/2014/03/ssl-tls-improvements-in-java-8.html">
-- * Significant SSL/TLS improvements in Java 8</a>
-- */
-- private static final boolean JDK_REJECT_CLIENT_INITIATED_RENEGOTIATION =
-- AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
-- @Override
-- public Boolean run() {
-- return SystemPropertyUtil.getBoolean("jdk.tls.rejectClientInitiatedRenegotiation", false);
-- }
-- });
+-public final class OpenSslServerSessionContext extends OpenSslSessionContext {
+- OpenSslServerSessionContext(ReferenceCountedOpenSslContext context, OpenSslKeyMaterialProvider provider) {
+- super(context, provider);
+- }
-
-- private static final int DEFAULT_BIO_NON_APPLICATION_BUFFER_SIZE =
-- AccessController.doPrivileged(new PrivilegedAction<Integer>() {
-- @Override
-- public Integer run() {
-- return Math.max(1,
-- SystemPropertyUtil.getInt("io.netty.handler.ssl.openssl.bioNonApplicationBufferSize",
-- 2048));
-- }
-- });
+- @Override
+- public void setSessionTimeout(int seconds) {
+- if (seconds < 0) {
+- throw new IllegalArgumentException();
+- }
+- Lock writerLock = context.ctxLock.writeLock();
+- writerLock.lock();
+- try {
+- SSLContext.setSessionCacheTimeout(context.ctx, seconds);
+- } finally {
+- writerLock.unlock();
+- }
+- }
-
-- private static final List<String> DEFAULT_CIPHERS;
-- private static final Integer DH_KEY_LENGTH;
-- private static final ResourceLeakDetector<ReferenceCountedOpenSslContext> leakDetector =
-- ResourceLeakDetectorFactory.instance().newResourceLeakDetector(ReferenceCountedOpenSslContext.class);
+- @Override
+- public int getSessionTimeout() {
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- try {
+- return (int) SSLContext.getSessionCacheTimeout(context.ctx);
+- } finally {
+- readerLock.unlock();
+- }
+- }
-
-- // TODO: Maybe make configurable ?
-- protected static final int VERIFY_DEPTH = 10;
+- @Override
+- public void setSessionCacheSize(int size) {
+- if (size < 0) {
+- throw new IllegalArgumentException();
+- }
+- Lock writerLock = context.ctxLock.writeLock();
+- writerLock.lock();
+- try {
+- SSLContext.setSessionCacheSize(context.ctx, size);
+- } finally {
+- writerLock.unlock();
+- }
+- }
-
-- /**
-- * The OpenSSL SSL_CTX object.
-- *
-- * <strong>{@link #ctxLock} must be hold while using ctx!</strong>
-- */
-- protected long ctx;
-- private final List<String> unmodifiableCiphers;
-- private final long sessionCacheSize;
-- private final long sessionTimeout;
-- private final OpenSslApplicationProtocolNegotiator apn;
-- private final int mode;
+- @Override
+- public int getSessionCacheSize() {
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- try {
+- return (int) SSLContext.getSessionCacheSize(context.ctx);
+- } finally {
+- readerLock.unlock();
+- }
+- }
-
-- // Reference Counting
-- private final ResourceLeakTracker<ReferenceCountedOpenSslContext> leak;
-- private final AbstractReferenceCounted refCnt = new AbstractReferenceCounted() {
-- @Override
-- public ReferenceCounted touch(Object hint) {
-- if (leak != null) {
-- leak.record(hint);
-- }
+- @Override
+- public void setSessionCacheEnabled(boolean enabled) {
+- long mode = enabled ? SSL.SSL_SESS_CACHE_SERVER : SSL.SSL_SESS_CACHE_OFF;
-
-- return ReferenceCountedOpenSslContext.this;
+- Lock writerLock = context.ctxLock.writeLock();
+- writerLock.lock();
+- try {
+- SSLContext.setSessionCacheMode(context.ctx, mode);
+- } finally {
+- writerLock.unlock();
- }
+- }
-
-- @Override
-- protected void deallocate() {
-- destroy();
-- if (leak != null) {
-- boolean closed = leak.close(ReferenceCountedOpenSslContext.this);
-- assert closed;
-- }
+- @Override
+- public boolean isSessionCacheEnabled() {
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- try {
+- return SSLContext.getSessionCacheMode(context.ctx) == SSL.SSL_SESS_CACHE_SERVER;
+- } finally {
+- readerLock.unlock();
- }
-- };
--
-- final Certificate[] keyCertChain;
-- final ClientAuth clientAuth;
-- final String[] protocols;
-- final boolean enableOcsp;
-- final OpenSslEngineMap engineMap = new DefaultOpenSslEngineMap();
-- final ReadWriteLock ctxLock = new ReentrantReadWriteLock();
--
-- private volatile boolean rejectRemoteInitiatedRenegotiation;
-- private volatile int bioNonApplicationBufferSize = DEFAULT_BIO_NON_APPLICATION_BUFFER_SIZE;
+- }
-
-- static final OpenSslApplicationProtocolNegotiator NONE_PROTOCOL_NEGOTIATOR =
-- new OpenSslApplicationProtocolNegotiator() {
-- @Override
-- public ApplicationProtocolConfig.Protocol protocol() {
-- return ApplicationProtocolConfig.Protocol.NONE;
-- }
+- /**
+- * Set the context within which session be reused (server side only)
+- * See <a href="http://www.openssl.org/docs/ssl/SSL_CTX_set_session_id_context.html">
+- * man SSL_CTX_set_session_id_context</a>
+- *
+- * @param sidCtx can be any kind of binary data, it is therefore possible to use e.g. the name
+- * of the application and/or the hostname and/or service name
+- * @return {@code true} if success, {@code false} otherwise.
+- */
+- public boolean setSessionIdContext(byte[] sidCtx) {
+- Lock writerLock = context.ctxLock.writeLock();
+- writerLock.lock();
+- try {
+- return SSLContext.setSessionIdContext(context.ctx, sidCtx);
+- } finally {
+- writerLock.unlock();
+- }
+- }
+-}
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionContext.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionContext.java
+deleted file mode 100644
+index 5d471d34fb..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionContext.java
++++ /dev/null
+@@ -1,158 +0,0 @@
+-/*
+- * Copyright 2014 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- * http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-package io.netty.handler.ssl;
-
-- @Override
-- public List<String> protocols() {
-- return Collections.emptyList();
-- }
+-import io.netty.internal.tcnative.SSL;
+-import io.netty.internal.tcnative.SSLContext;
+-import io.netty.internal.tcnative.SessionTicketKey;
+-import io.netty.util.internal.ObjectUtil;
-
-- @Override
-- public ApplicationProtocolConfig.SelectorFailureBehavior selectorFailureBehavior() {
-- return ApplicationProtocolConfig.SelectorFailureBehavior.CHOOSE_MY_LAST_PROTOCOL;
-- }
+-import javax.net.ssl.SSLSession;
+-import javax.net.ssl.SSLSessionContext;
+-import java.util.Arrays;
+-import java.util.Enumeration;
+-import java.util.NoSuchElementException;
+-import java.util.concurrent.locks.Lock;
-
-- @Override
-- public ApplicationProtocolConfig.SelectedListenerFailureBehavior selectedListenerFailureBehavior() {
-- return ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT;
-- }
-- };
+-/**
+- * OpenSSL specific {@link SSLSessionContext} implementation.
+- */
+-public abstract class OpenSslSessionContext implements SSLSessionContext {
+- private static final Enumeration<byte[]> EMPTY = new EmptyEnumeration();
-
-- static {
-- List<String> ciphers = new ArrayList<String>();
-- // XXX: Make sure to sync this list with JdkSslEngineFactory.
-- Collections.addAll(
-- ciphers,
-- "ECDHE-ECDSA-AES256-GCM-SHA384",
-- "ECDHE-ECDSA-AES128-GCM-SHA256",
-- "ECDHE-RSA-AES128-GCM-SHA256",
-- "ECDHE-RSA-AES128-SHA",
-- "ECDHE-RSA-AES256-SHA",
-- "AES128-GCM-SHA256",
-- "AES128-SHA",
-- "AES256-SHA");
-- DEFAULT_CIPHERS = Collections.unmodifiableList(ciphers);
+- private final OpenSslSessionStats stats;
-
-- if (logger.isDebugEnabled()) {
-- logger.debug("Default cipher suite (OpenSSL): " + ciphers);
-- }
+- // The OpenSslKeyMaterialProvider is not really used by the OpenSslSessionContext but only be stored here
+- // to make it easier to destroy it later because the ReferenceCountedOpenSslContext will hold a reference
+- // to OpenSslSessionContext.
+- private final OpenSslKeyMaterialProvider provider;
-
-- Integer dhLen = null;
+- final ReferenceCountedOpenSslContext context;
-
-- try {
-- String dhKeySize = AccessController.doPrivileged(new PrivilegedAction<String>() {
-- @Override
-- public String run() {
-- return SystemPropertyUtil.get("jdk.tls.ephemeralDHKeySize");
-- }
-- });
-- if (dhKeySize != null) {
-- try {
-- dhLen = Integer.valueOf(dhKeySize);
-- } catch (NumberFormatException e) {
-- logger.debug("ReferenceCountedOpenSslContext supports -Djdk.tls.ephemeralDHKeySize={int}, but got: "
-- + dhKeySize);
-- }
-- }
-- } catch (Throwable ignore) {
-- // ignore
-- }
-- DH_KEY_LENGTH = dhLen;
+- // IMPORTANT: We take the OpenSslContext and not just the long (which points the native instance) to prevent
+- // the GC to collect OpenSslContext as this would also free the pointer and so could result in a
+- // segfault when the user calls any of the methods here that try to pass the pointer down to the native
+- // level.
+- OpenSslSessionContext(ReferenceCountedOpenSslContext context, OpenSslKeyMaterialProvider provider) {
+- this.context = context;
+- this.provider = provider;
+- stats = new OpenSslSessionStats(context);
- }
-
-- ReferenceCountedOpenSslContext(Iterable<String> ciphers, CipherSuiteFilter cipherFilter,
-- ApplicationProtocolConfig apnCfg, long sessionCacheSize, long sessionTimeout,
-- int mode, Certificate[] keyCertChain, ClientAuth clientAuth, String[] protocols,
-- boolean startTls, boolean enableOcsp, boolean leakDetection) throws SSLException {
-- this(ciphers, cipherFilter, toNegotiator(apnCfg), sessionCacheSize, sessionTimeout, mode, keyCertChain,
-- clientAuth, protocols, startTls, enableOcsp, leakDetection);
+- final boolean useKeyManager() {
+- return provider != null;
- }
-
-- ReferenceCountedOpenSslContext(Iterable<String> ciphers, CipherSuiteFilter cipherFilter,
-- OpenSslApplicationProtocolNegotiator apn, long sessionCacheSize,
-- long sessionTimeout, int mode, Certificate[] keyCertChain,
-- ClientAuth clientAuth, String[] protocols, boolean startTls, boolean enableOcsp,
-- boolean leakDetection) throws SSLException {
-- super(startTls);
+- @Override
+- public SSLSession getSession(byte[] bytes) {
+- ObjectUtil.checkNotNull(bytes, "bytes");
+- return null;
+- }
-
-- OpenSsl.ensureAvailability();
+- @Override
+- public Enumeration<byte[]> getIds() {
+- return EMPTY;
+- }
-
-- if (enableOcsp && !OpenSsl.isOcspSupported()) {
-- throw new IllegalStateException("OCSP is not supported.");
+- /**
+- * Sets the SSL session ticket keys of this context.
+- * @deprecated use {@link #setTicketKeys(OpenSslSessionTicketKey...)}.
+- */
+- @Deprecated
+- public void setTicketKeys(byte[] keys) {
+- if (keys.length % SessionTicketKey.TICKET_KEY_SIZE != 0) {
+- throw new IllegalArgumentException("keys.length % " + SessionTicketKey.TICKET_KEY_SIZE + " != 0");
- }
--
-- if (mode != SSL.SSL_MODE_SERVER && mode != SSL.SSL_MODE_CLIENT) {
-- throw new IllegalArgumentException("mode most be either SSL.SSL_MODE_SERVER or SSL.SSL_MODE_CLIENT");
+- SessionTicketKey[] tickets = new SessionTicketKey[keys.length / SessionTicketKey.TICKET_KEY_SIZE];
+- for (int i = 0, a = 0; i < tickets.length; i++) {
+- byte[] name = Arrays.copyOfRange(keys, a, SessionTicketKey.NAME_SIZE);
+- a += SessionTicketKey.NAME_SIZE;
+- byte[] hmacKey = Arrays.copyOfRange(keys, a, SessionTicketKey.HMAC_KEY_SIZE);
+- i += SessionTicketKey.HMAC_KEY_SIZE;
+- byte[] aesKey = Arrays.copyOfRange(keys, a, SessionTicketKey.AES_KEY_SIZE);
+- a += SessionTicketKey.AES_KEY_SIZE;
+- tickets[i] = new SessionTicketKey(name, hmacKey, aesKey);
- }
-- leak = leakDetection ? leakDetector.track(this) : null;
-- this.mode = mode;
-- this.clientAuth = isServer() ? checkNotNull(clientAuth, "clientAuth") : ClientAuth.NONE;
-- this.protocols = protocols;
-- this.enableOcsp = enableOcsp;
--
-- if (mode == SSL.SSL_MODE_SERVER) {
-- rejectRemoteInitiatedRenegotiation =
-- JDK_REJECT_CLIENT_INITIATED_RENEGOTIATION;
+- Lock writerLock = context.ctxLock.writeLock();
+- writerLock.lock();
+- try {
+- SSLContext.clearOptions(context.ctx, SSL.SSL_OP_NO_TICKET);
+- SSLContext.setSessionTicketKeys(context.ctx, tickets);
+- } finally {
+- writerLock.unlock();
- }
-- this.keyCertChain = keyCertChain == null ? null : keyCertChain.clone();
-- final List<String> convertedCiphers;
-- if (ciphers == null) {
-- convertedCiphers = null;
-- } else {
-- convertedCiphers = new ArrayList<String>();
-- for (String c : ciphers) {
-- if (c == null) {
-- break;
-- }
+- }
-
-- String converted = CipherSuiteConverter.toOpenSsl(c);
-- if (converted != null) {
-- c = converted;
-- }
-- convertedCiphers.add(c);
+- /**
+- * Sets the SSL session ticket keys of this context. Depending on the underlying native library you may omit the
+- * argument or pass an empty array and so let the native library handle the key generation and rotating for you.
+- * If this is supported by the underlying native library should be checked in this case. For example
+- * <a href="https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.ht...">
+- * BoringSSL</a> is known to support this.
+- */
+- public void setTicketKeys(OpenSslSessionTicketKey... keys) {
+- ObjectUtil.checkNotNull(keys, "keys");
+- SessionTicketKey[] ticketKeys = new SessionTicketKey[keys.length];
+- for (int i = 0; i < ticketKeys.length; i++) {
+- ticketKeys[i] = keys[i].key;
+- }
+- Lock writerLock = context.ctxLock.writeLock();
+- writerLock.lock();
+- try {
+- SSLContext.clearOptions(context.ctx, SSL.SSL_OP_NO_TICKET);
+- if (ticketKeys.length > 0) {
+- SSLContext.setSessionTicketKeys(context.ctx, ticketKeys);
- }
+- } finally {
+- writerLock.unlock();
- }
+- }
-
-- unmodifiableCiphers = Arrays.asList(checkNotNull(cipherFilter, "cipherFilter").filterCipherSuites(
-- convertedCiphers, DEFAULT_CIPHERS, OpenSsl.availableOpenSslCipherSuites()));
+- /**
+- * Enable or disable caching of SSL sessions.
+- */
+- public abstract void setSessionCacheEnabled(boolean enabled);
-
-- this.apn = checkNotNull(apn, "apn");
+- /**
+- * Return {@code true} if caching of SSL sessions is enabled, {@code false} otherwise.
+- */
+- public abstract boolean isSessionCacheEnabled();
-
-- // Create a new SSL_CTX and configure it.
-- boolean success = false;
-- try {
-- try {
-- ctx = SSLContext.make(SSL.SSL_PROTOCOL_ALL, mode);
-- } catch (Exception e) {
-- throw new SSLException("failed to create an SSL_CTX", e);
-- }
+- /**
+- * Returns the stats of this context.
+- */
+- public OpenSslSessionStats stats() {
+- return stats;
+- }
+-
+- final void destroy() {
+- if (provider != null) {
+- provider.destroy();
+- }
+- }
+-
+- private static final class EmptyEnumeration implements Enumeration<byte[]> {
+- @Override
+- public boolean hasMoreElements() {
+- return false;
+- }
-
-- SSLContext.setOptions(ctx, SSLContext.getOptions(ctx) |
-- SSL.SSL_OP_NO_SSLv2 |
-- SSL.SSL_OP_NO_SSLv3 |
-- SSL.SSL_OP_CIPHER_SERVER_PREFERENCE |
+- @Override
+- public byte[] nextElement() {
+- throw new NoSuchElementException();
+- }
+- }
+-}
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionStats.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionStats.java
+deleted file mode 100644
+index f49b95f3ba..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionStats.java
++++ /dev/null
+@@ -1,253 +0,0 @@
+-/*
+- * Copyright 2014 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- * http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
-
-- // We do not support compression at the moment so we should explicitly disable it.
-- SSL.SSL_OP_NO_COMPRESSION |
+-package io.netty.handler.ssl;
-
-- // Disable ticket support by default to be more inline with SSLEngineImpl of the JDK.
-- // This also let SSLSession.getId() work the same way for the JDK implementation and the
-- // OpenSSLEngine. If tickets are supported SSLSession.getId() will only return an ID on the
-- // server-side if it could make use of tickets.
-- SSL.SSL_OP_NO_TICKET);
+-import io.netty.internal.tcnative.SSLContext;
-
-- // We need to enable SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER as the memory address may change between
-- // calling OpenSSLEngine.wrap(...).
-- // See https://github.com/netty/netty-tcnative/issues/100
-- SSLContext.setMode(ctx, SSLContext.getMode(ctx) | SSL.SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
+-import java.util.concurrent.locks.Lock;
-
-- if (DH_KEY_LENGTH != null) {
-- SSLContext.setTmpDHLength(ctx, DH_KEY_LENGTH);
-- }
+-/**
+- * Stats exposed by an OpenSSL session context.
+- *
+- * @see <a href="https://www.openssl.org/docs/manmaster/man3/SSL_CTX_sess_number.html">SSL_CTX_sess_number</a>
+- */
+-public final class OpenSslSessionStats {
-
-- /* List the ciphers that are permitted to negotiate. */
-- try {
-- SSLContext.setCipherSuite(ctx, CipherSuiteConverter.toOpenSsl(unmodifiableCiphers));
-- } catch (SSLException e) {
-- throw e;
-- } catch (Exception e) {
-- throw new SSLException("failed to set cipher suite: " + unmodifiableCiphers, e);
-- }
+- private final ReferenceCountedOpenSslContext context;
-
-- List<String> nextProtoList = apn.protocols();
-- /* Set next protocols for next protocol negotiation extension, if specified */
-- if (!nextProtoList.isEmpty()) {
-- String[] appProtocols = nextProtoList.toArray(new String[nextProtoList.size()]);
-- int selectorBehavior = opensslSelectorFailureBehavior(apn.selectorFailureBehavior());
+- // IMPORTANT: We take the OpenSslContext and not just the long (which points the native instance) to prevent
+- // the GC to collect OpenSslContext as this would also free the pointer and so could result in a
+- // segfault when the user calls any of the methods here that try to pass the pointer down to the native
+- // level.
+- OpenSslSessionStats(ReferenceCountedOpenSslContext context) {
+- this.context = context;
+- }
-
-- switch (apn.protocol()) {
-- case NPN:
-- SSLContext.setNpnProtos(ctx, appProtocols, selectorBehavior);
-- break;
-- case ALPN:
-- SSLContext.setAlpnProtos(ctx, appProtocols, selectorBehavior);
-- break;
-- case NPN_AND_ALPN:
-- SSLContext.setNpnProtos(ctx, appProtocols, selectorBehavior);
-- SSLContext.setAlpnProtos(ctx, appProtocols, selectorBehavior);
-- break;
-- default:
-- throw new Error();
-- }
-- }
+- /**
+- * Returns the current number of sessions in the internal session cache.
+- */
+- public long number() {
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- try {
+- return SSLContext.sessionNumber(context.ctx);
+- } finally {
+- readerLock.unlock();
+- }
+- }
-
-- /* Set session cache size, if specified */
-- if (sessionCacheSize > 0) {
-- this.sessionCacheSize = sessionCacheSize;
-- SSLContext.setSessionCacheSize(ctx, sessionCacheSize);
-- } else {
-- // Get the default session cache size using SSLContext.setSessionCacheSize()
-- this.sessionCacheSize = sessionCacheSize = SSLContext.setSessionCacheSize(ctx, 20480);
-- // Revert the session cache size to the default value.
-- SSLContext.setSessionCacheSize(ctx, sessionCacheSize);
-- }
+- /**
+- * Returns the number of started SSL/TLS handshakes in client mode.
+- */
+- public long connect() {
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- try {
+- return SSLContext.sessionConnect(context.ctx);
+- } finally {
+- readerLock.unlock();
+- }
+- }
-
-- /* Set session timeout, if specified */
-- if (sessionTimeout > 0) {
-- this.sessionTimeout = sessionTimeout;
-- SSLContext.setSessionCacheTimeout(ctx, sessionTimeout);
-- } else {
-- // Get the default session timeout using SSLContext.setSessionCacheTimeout()
-- this.sessionTimeout = sessionTimeout = SSLContext.setSessionCacheTimeout(ctx, 300);
-- // Revert the session timeout to the default value.
-- SSLContext.setSessionCacheTimeout(ctx, sessionTimeout);
-- }
+- /**
+- * Returns the number of successfully established SSL/TLS sessions in client mode.
+- */
+- public long connectGood() {
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- try {
+- return SSLContext.sessionConnectGood(context.ctx);
+- } finally {
+- readerLock.unlock();
+- }
+- }
-
-- if (enableOcsp) {
-- SSLContext.enableOcsp(ctx, isClient());
-- }
-- success = true;
+- /**
+- * Returns the number of start renegotiations in client mode.
+- */
+- public long connectRenegotiate() {
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- try {
+- return SSLContext.sessionConnectRenegotiate(context.ctx);
- } finally {
-- if (!success) {
-- release();
-- }
+- readerLock.unlock();
- }
- }
-
-- private static int opensslSelectorFailureBehavior(ApplicationProtocolConfig.SelectorFailureBehavior behavior) {
-- switch (behavior) {
-- case NO_ADVERTISE:
-- return SSL.SSL_SELECTOR_FAILURE_NO_ADVERTISE;
-- case CHOOSE_MY_LAST_PROTOCOL:
-- return SSL.SSL_SELECTOR_FAILURE_CHOOSE_MY_LAST_PROTOCOL;
-- default:
-- throw new Error();
+- /**
+- * Returns the number of started SSL/TLS handshakes in server mode.
+- */
+- public long accept() {
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- try {
+- return SSLContext.sessionAccept(context.ctx);
+- } finally {
+- readerLock.unlock();
- }
- }
-
-- @Override
-- public final List<String> cipherSuites() {
-- return unmodifiableCiphers;
+- /**
+- * Returns the number of successfully established SSL/TLS sessions in server mode.
+- */
+- public long acceptGood() {
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- try {
+- return SSLContext.sessionAcceptGood(context.ctx);
+- } finally {
+- readerLock.unlock();
+- }
- }
-
-- @Override
-- public final long sessionCacheSize() {
-- return sessionCacheSize;
+- /**
+- * Returns the number of start renegotiations in server mode.
+- */
+- public long acceptRenegotiate() {
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- try {
+- return SSLContext.sessionAcceptRenegotiate(context.ctx);
+- } finally {
+- readerLock.unlock();
+- }
- }
-
-- @Override
-- public final long sessionTimeout() {
-- return sessionTimeout;
+- /**
+- * Returns the number of successfully reused sessions. In client mode, a session set with {@code SSL_set_session}
+- * successfully reused is counted as a hit. In server mode, a session successfully retrieved from internal or
+- * external cache is counted as a hit.
+- */
+- public long hits() {
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- try {
+- return SSLContext.sessionHits(context.ctx);
+- } finally {
+- readerLock.unlock();
+- }
- }
-
-- @Override
-- public ApplicationProtocolNegotiator applicationProtocolNegotiator() {
-- return apn;
+- /**
+- * Returns the number of successfully retrieved sessions from the external session cache in server mode.
+- */
+- public long cbHits() {
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- try {
+- return SSLContext.sessionCbHits(context.ctx);
+- } finally {
+- readerLock.unlock();
+- }
- }
-
-- @Override
-- public final boolean isClient() {
-- return mode == SSL.SSL_MODE_CLIENT;
+- /**
+- * Returns the number of sessions proposed by clients that were not found in the internal session cache
+- * in server mode.
+- */
+- public long misses() {
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- try {
+- return SSLContext.sessionMisses(context.ctx);
+- } finally {
+- readerLock.unlock();
+- }
- }
-
-- @Override
-- public final SSLEngine newEngine(ByteBufAllocator alloc, String peerHost, int peerPort) {
-- return newEngine0(alloc, peerHost, peerPort);
+- /**
+- * Returns the number of sessions proposed by clients and either found in the internal or external session cache
+- * in server mode, but that were invalid due to timeout. These sessions are not included in the {@link #hits()}
+- * count.
+- */
+- public long timeouts() {
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- try {
+- return SSLContext.sessionTimeouts(context.ctx);
+- } finally {
+- readerLock.unlock();
+- }
- }
-
-- SSLEngine newEngine0(ByteBufAllocator alloc, String peerHost, int peerPort) {
-- return new ReferenceCountedOpenSslEngine(this, alloc, peerHost, peerPort, true);
+- /**
+- * Returns the number of sessions that were removed because the maximum session cache size was exceeded.
+- */
+- public long cacheFull() {
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- try {
+- return SSLContext.sessionCacheFull(context.ctx);
+- } finally {
+- readerLock.unlock();
+- }
- }
-
-- abstract OpenSslKeyMaterialManager keyMaterialManager();
+- /**
+- * Returns the number of times a client presented a ticket that did not match any key in the list.
+- */
+- public long ticketKeyFail() {
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- try {
+- return SSLContext.sessionTicketKeyFail(context.ctx);
+- } finally {
+- readerLock.unlock();
+- }
+- }
-
- /**
-- * Returns a new server-side {@link SSLEngine} with the current configuration.
+- * Returns the number of times a client did not present a ticket and we issued a new one
- */
-- @Override
-- public final SSLEngine newEngine(ByteBufAllocator alloc) {
-- return newEngine(alloc, null, -1);
+- public long ticketKeyNew() {
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- try {
+- return SSLContext.sessionTicketKeyNew(context.ctx);
+- } finally {
+- readerLock.unlock();
+- }
- }
-
- /**
-- * Returns the pointer to the {@code SSL_CTX} object for this {@link ReferenceCountedOpenSslContext}.
-- * Be aware that it is freed as soon as the {@link #finalize()} method is called.
-- * At this point {@code 0} will be returned.
-- *
-- * @deprecated this method is considered unsafe as the returned pointer may be released later. Dont use it!
+- * Returns the number of times a client presented a ticket derived from an older key,
+- * and we upgraded to the primary key.
- */
-- @Deprecated
-- public final long context() {
-- Lock readerLock = ctxLock.readLock();
+- public long ticketKeyRenew() {
+- Lock readerLock = context.ctxLock.readLock();
- readerLock.lock();
- try {
-- return ctx;
+- return SSLContext.sessionTicketKeyRenew(context.ctx);
- } finally {
- readerLock.unlock();
- }
- }
-
- /**
-- * Returns the stats of this context.
-- *
-- * @deprecated use {@link #sessionContext#stats()}
+- * Returns the number of times a client presented a ticket derived from the primary key.
- */
-- @Deprecated
-- public final OpenSslSessionStats stats() {
-- return sessionContext().stats();
+- public long ticketKeyResume() {
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- try {
+- return SSLContext.sessionTicketKeyResume(context.ctx);
+- } finally {
+- readerLock.unlock();
+- }
- }
+-}
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionTicketKey.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionTicketKey.java
+deleted file mode 100644
+index 79f71a65a3..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionTicketKey.java
++++ /dev/null
+@@ -1,78 +0,0 @@
+-/*
+- * Copyright 2015 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- * http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-package io.netty.handler.ssl;
+-
+-import io.netty.internal.tcnative.SessionTicketKey;
+-
+-/**
+- * Session Ticket Key
+- */
+-public final class OpenSslSessionTicketKey {
-
- /**
-- * Specify if remote initiated renegotiation is supported or not. If not supported and the remote side tries
-- * to initiate a renegotiation a {@link SSLHandshakeException} will be thrown during decoding.
+- * Size of session ticket key name
+- */
+- public static final int NAME_SIZE = SessionTicketKey.NAME_SIZE;
+- /**
+- * Size of session ticket key HMAC key
+- */
+- public static final int HMAC_KEY_SIZE = SessionTicketKey.HMAC_KEY_SIZE;
+- /**
+- * Size of session ticket key AES key
- */
-- public void setRejectRemoteInitiatedRenegotiation(boolean rejectRemoteInitiatedRenegotiation) {
-- this.rejectRemoteInitiatedRenegotiation = rejectRemoteInitiatedRenegotiation;
-- }
--
+- public static final int AES_KEY_SIZE = SessionTicketKey.AES_KEY_SIZE;
- /**
-- * Returns if remote initiated renegotiation is supported or not.
+- * Size of session ticker key
- */
-- public boolean getRejectRemoteInitiatedRenegotiation() {
-- return rejectRemoteInitiatedRenegotiation;
-- }
+- public static final int TICKET_KEY_SIZE = SessionTicketKey.TICKET_KEY_SIZE;
+-
+- final SessionTicketKey key;
-
- /**
-- * Set the size of the buffer used by the BIO for non-application based writes
-- * (e.g. handshake, renegotiation, etc...).
+- * Construct a OpenSslSessionTicketKey.
+- *
+- * @param name the name of the session ticket key
+- * @param hmacKey the HMAC key of the session ticket key
+- * @param aesKey the AES key of the session ticket key
- */
-- public void setBioNonApplicationBufferSize(int bioNonApplicationBufferSize) {
-- this.bioNonApplicationBufferSize =
-- checkPositiveOrZero(bioNonApplicationBufferSize, "bioNonApplicationBufferSize");
+- public OpenSslSessionTicketKey(byte[] name, byte[] hmacKey, byte[] aesKey) {
+- key = new SessionTicketKey(name.clone(), hmacKey.clone(), aesKey.clone());
- }
-
- /**
-- * Returns the size of the buffer used by the BIO for non-application based writes
+- * Get name.
+- * @return the name of the session ticket key
- */
-- public int getBioNonApplicationBufferSize() {
-- return bioNonApplicationBufferSize;
+- public byte[] name() {
+- return key.getName().clone();
- }
-
- /**
-- * Sets the SSL session ticket keys of this context.
-- *
-- * @deprecated use {@link OpenSslSessionContext#setTicketKeys(byte[])}
+- * Get HMAC key.
+- * @return the HMAC key of the session ticket key
- */
-- @Deprecated
-- public final void setTicketKeys(byte[] keys) {
-- sessionContext().setTicketKeys(keys);
+- public byte[] hmacKey() {
+- return key.getHmacKey().clone();
- }
-
-- @Override
-- public abstract OpenSslSessionContext sessionContext();
--
- /**
-- * Returns the pointer to the {@code SSL_CTX} object for this {@link ReferenceCountedOpenSslContext}.
-- * Be aware that it is freed as soon as the {@link #release()} method is called.
-- * At this point {@code 0} will be returned.
-- *
-- * @deprecated this method is considered unsafe as the returned pointer may be released later. Dont use it!
+- * Get AES Key.
+- * @return the AES key of the session ticket key
- */
-- @Deprecated
-- public final long sslCtxPointer() {
-- Lock readerLock = ctxLock.readLock();
-- readerLock.lock();
-- try {
-- return ctx;
-- } finally {
-- readerLock.unlock();
-- }
+- public byte[] aesKey() {
+- return key.getAesKey().clone();
- }
+-}
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslTlsv13X509ExtendedTrustManager.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslTlsv13X509ExtendedTrustManager.java
+deleted file mode 100644
+index a5a84f2793..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslTlsv13X509ExtendedTrustManager.java
++++ /dev/null
+@@ -1,240 +0,0 @@
+-/*
+- * Copyright 2018 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- * http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-package io.netty.handler.ssl;
-
-- // IMPORTANT: This method must only be called from either the constructor or the finalizer as a user MUST never
-- // get access to an OpenSslSessionContext after this method was called to prevent the user from
-- // producing a segfault.
-- private void destroy() {
-- Lock writerLock = ctxLock.writeLock();
-- writerLock.lock();
-- try {
-- if (ctx != 0) {
-- if (enableOcsp) {
-- SSLContext.disableOcsp(ctx);
-- }
+-import io.netty.util.internal.PlatformDependent;
+-import io.netty.util.internal.SuppressJava6Requirement;
-
-- SSLContext.free(ctx);
-- ctx = 0;
-- }
-- } finally {
-- writerLock.unlock();
-- }
-- }
+-import javax.net.ssl.SSLEngine;
+-import javax.net.ssl.SSLPeerUnverifiedException;
+-import javax.net.ssl.SSLSession;
+-import javax.net.ssl.SSLSessionContext;
+-import javax.net.ssl.X509ExtendedTrustManager;
+-import java.net.Socket;
+-import java.security.Principal;
+-import java.security.cert.Certificate;
+-import java.security.cert.CertificateException;
+-import java.security.cert.X509Certificate;
+-import java.util.List;
-
-- protected static X509Certificate[] certificates(byte[][] chain) {
-- X509Certificate[] peerCerts = new X509Certificate[chain.length];
-- for (int i = 0; i < peerCerts.length; i++) {
-- peerCerts[i] = new OpenSslX509Certificate(chain[i]);
-- }
-- return peerCerts;
-- }
+-/**
+- * Provide a way to use {@code TLSv1.3} with Java versions prior to 11 by adding a
+- * <a href="http://mail.openjdk.java.net/pipermail/security-dev/2018-September/018242...>workaround</a> for the
+- * default {@link X509ExtendedTrustManager} implementations provided by the JDK that can not handle a protocol version
+- * of {@code TLSv1.3}.
+- */
+-@SuppressJava6Requirement(reason = "Usage guarded by java version check")
+-final class OpenSslTlsv13X509ExtendedTrustManager extends X509ExtendedTrustManager {
-
-- protected static X509TrustManager chooseTrustManager(TrustManager[] managers) {
-- for (TrustManager m : managers) {
-- if (m instanceof X509TrustManager) {
-- return (X509TrustManager) m;
-- }
-- }
-- throw new IllegalStateException("no X509TrustManager found");
-- }
+- private final X509ExtendedTrustManager tm;
-
-- protected static X509KeyManager chooseX509KeyManager(KeyManager[] kms) {
-- for (KeyManager km : kms) {
-- if (km instanceof X509KeyManager) {
-- return (X509KeyManager) km;
-- }
-- }
-- throw new IllegalStateException("no X509KeyManager found");
+- private OpenSslTlsv13X509ExtendedTrustManager(X509ExtendedTrustManager tm) {
+- this.tm = tm;
- }
-
-- /**
-- * Translate a {@link ApplicationProtocolConfig} object to a
-- * {@link OpenSslApplicationProtocolNegotiator} object.
-- *
-- * @param config The configuration which defines the translation
-- * @return The results of the translation
-- */
-- static OpenSslApplicationProtocolNegotiator toNegotiator(ApplicationProtocolConfig config) {
-- if (config == null) {
-- return NONE_PROTOCOL_NEGOTIATOR;
-- }
--
-- switch (config.protocol()) {
-- case NONE:
-- return NONE_PROTOCOL_NEGOTIATOR;
-- case ALPN:
-- case NPN:
-- case NPN_AND_ALPN:
-- switch (config.selectedListenerFailureBehavior()) {
-- case CHOOSE_MY_LAST_PROTOCOL:
-- case ACCEPT:
-- switch (config.selectorFailureBehavior()) {
-- case CHOOSE_MY_LAST_PROTOCOL:
-- case NO_ADVERTISE:
-- return new OpenSslDefaultApplicationProtocolNegotiator(
-- config);
-- default:
-- throw new UnsupportedOperationException(
-- new StringBuilder("OpenSSL provider does not support ")
-- .append(config.selectorFailureBehavior())
-- .append(" behavior").toString());
-- }
-- default:
-- throw new UnsupportedOperationException(
-- new StringBuilder("OpenSSL provider does not support ")
-- .append(config.selectedListenerFailureBehavior())
-- .append(" behavior").toString());
-- }
-- default:
-- throw new Error();
+- static X509ExtendedTrustManager wrap(X509ExtendedTrustManager tm) {
+- if (PlatformDependent.javaVersion() < 11 && OpenSsl.isTlsv13Supported()) {
+- return new OpenSslTlsv13X509ExtendedTrustManager(tm);
- }
-- }
--
-- static boolean useExtendedTrustManager(X509TrustManager trustManager) {
-- return PlatformDependent.javaVersion() >= 7 && trustManager instanceof X509ExtendedTrustManager;
-- }
--
-- static boolean useExtendedKeyManager(X509KeyManager keyManager) {
-- return PlatformDependent.javaVersion() >= 7 && keyManager instanceof X509ExtendedKeyManager;
-- }
--
-- @Override
-- public final int refCnt() {
-- return refCnt.refCnt();
+- return tm;
- }
-
- @Override
-- public final ReferenceCounted retain() {
-- refCnt.retain();
-- return this;
-- }
--
-- @Override
-- public final ReferenceCounted retain(int increment) {
-- refCnt.retain(increment);
-- return this;
+- public void checkClientTrusted(X509Certificate[] x509Certificates, String s, Socket socket)
+- throws CertificateException {
+- tm.checkClientTrusted(x509Certificates, s, socket);
- }
-
- @Override
-- public final ReferenceCounted touch() {
-- refCnt.touch();
-- return this;
+- public void checkServerTrusted(X509Certificate[] x509Certificates, String s, Socket socket)
+- throws CertificateException {
+- tm.checkServerTrusted(x509Certificates, s, socket);
- }
-
-- @Override
-- public final ReferenceCounted touch(Object hint) {
-- refCnt.touch(hint);
-- return this;
-- }
+- private static SSLEngine wrapEngine(final SSLEngine engine) {
+- final SSLSession session = engine.getHandshakeSession();
+- if (session != null && SslUtils.PROTOCOL_TLS_V1_3.equals(session.getProtocol())) {
+- return new JdkSslEngine(engine) {
+- @Override
+- public String getNegotiatedApplicationProtocol() {
+- if (engine instanceof ApplicationProtocolAccessor) {
+- return ((ApplicationProtocolAccessor) engine).getNegotiatedApplicationProtocol();
+- }
+- return super.getNegotiatedApplicationProtocol();
+- }
-
-- @Override
-- public final boolean release() {
-- return refCnt.release();
-- }
+- @Override
+- public SSLSession getHandshakeSession() {
+- if (PlatformDependent.javaVersion() >= 7 && session instanceof ExtendedOpenSslSession) {
+- final ExtendedOpenSslSession extendedOpenSslSession = (ExtendedOpenSslSession) session;
+- return new ExtendedOpenSslSession(extendedOpenSslSession) {
+- @Override
+- public List getRequestedServerNames() {
+- return extendedOpenSslSession.getRequestedServerNames();
+- }
-
-- @Override
-- public final boolean release(int decrement) {
-- return refCnt.release(decrement);
-- }
+- @Override
+- public String[] getPeerSupportedSignatureAlgorithms() {
+- return extendedOpenSslSession.getPeerSupportedSignatureAlgorithms();
+- }
-
-- abstract static class AbstractCertificateVerifier extends CertificateVerifier {
-- private final OpenSslEngineMap engineMap;
+- @Override
+- public String getProtocol() {
+- return SslUtils.PROTOCOL_TLS_V1_2;
+- }
+- };
+- } else {
+- return new SSLSession() {
+- @Override
+- public byte[] getId() {
+- return session.getId();
+- }
-
-- AbstractCertificateVerifier(OpenSslEngineMap engineMap) {
-- this.engineMap = engineMap;
-- }
+- @Override
+- public SSLSessionContext getSessionContext() {
+- return session.getSessionContext();
+- }
-
-- @Override
-- public final int verify(long ssl, byte[][] chain, String auth) {
-- X509Certificate[] peerCerts = certificates(chain);
-- final ReferenceCountedOpenSslEngine engine = engineMap.get(ssl);
-- try {
-- verify(engine, peerCerts, auth);
-- return CertificateVerifier.X509_V_OK;
-- } catch (Throwable cause) {
-- logger.debug("verification of certificate failed", cause);
-- SSLHandshakeException e = new SSLHandshakeException("General OpenSslEngine problem");
-- e.initCause(cause);
-- engine.handshakeException = e;
+- @Override
+- public long getCreationTime() {
+- return session.getCreationTime();
+- }
-
-- // Try to extract the correct error code that should be used.
-- if (cause instanceof OpenSslCertificateException) {
-- // This will never return a negative error code as its validated when constructing the
-- // OpenSslCertificateException.
-- return ((OpenSslCertificateException) cause).errorCode();
-- }
-- if (cause instanceof CertificateExpiredException) {
-- return CertificateVerifier.X509_V_ERR_CERT_HAS_EXPIRED;
-- }
-- if (cause instanceof CertificateNotYetValidException) {
-- return CertificateVerifier.X509_V_ERR_CERT_NOT_YET_VALID;
-- }
-- if (PlatformDependent.javaVersion() >= 7) {
-- if (cause instanceof CertificateRevokedException) {
-- return CertificateVerifier.X509_V_ERR_CERT_REVOKED;
-- }
+- @Override
+- public long getLastAccessedTime() {
+- return session.getLastAccessedTime();
+- }
-
-- // The X509TrustManagerImpl uses a Validator which wraps a CertPathValidatorException into
-- // an CertificateException. So we need to handle the wrapped CertPathValidatorException to be
-- // able to send the correct alert.
-- Throwable wrapped = cause.getCause();
-- while (wrapped != null) {
-- if (wrapped instanceof CertPathValidatorException) {
-- CertPathValidatorException ex = (CertPathValidatorException) wrapped;
-- CertPathValidatorException.Reason reason = ex.getReason();
-- if (reason == CertPathValidatorException.BasicReason.EXPIRED) {
-- return CertificateVerifier.X509_V_ERR_CERT_HAS_EXPIRED;
+- @Override
+- public void invalidate() {
+- session.invalidate();
- }
-- if (reason == CertPathValidatorException.BasicReason.NOT_YET_VALID) {
-- return CertificateVerifier.X509_V_ERR_CERT_NOT_YET_VALID;
+-
+- @Override
+- public boolean isValid() {
+- return session.isValid();
- }
-- if (reason == CertPathValidatorException.BasicReason.REVOKED) {
-- return CertificateVerifier.X509_V_ERR_CERT_REVOKED;
+-
+- @Override
+- public void putValue(String s, Object o) {
+- session.putValue(s, o);
- }
-- }
-- wrapped = wrapped.getCause();
-- }
-- }
-
-- // Could not detect a specific error code to use, so fallback to a default code.
-- return CertificateVerifier.X509_V_ERR_UNSPECIFIED;
-- }
-- }
+- @Override
+- public Object getValue(String s) {
+- return session.getValue(s);
+- }
-
-- abstract void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts,
-- String auth) throws Exception;
-- }
+- @Override
+- public void removeValue(String s) {
+- session.removeValue(s);
+- }
-
-- private static final class DefaultOpenSslEngineMap implements OpenSslEngineMap {
-- private final Map<Long, ReferenceCountedOpenSslEngine> engines = PlatformDependent.newConcurrentHashMap();
+- @Override
+- public String[] getValueNames() {
+- return session.getValueNames();
+- }
-
-- @Override
-- public ReferenceCountedOpenSslEngine remove(long ssl) {
-- return engines.remove(ssl);
-- }
+- @Override
+- public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException {
+- return session.getPeerCertificates();
+- }
-
-- @Override
-- public void add(ReferenceCountedOpenSslEngine engine) {
-- engines.put(engine.sslPointer(), engine);
-- }
+- @Override
+- public Certificate[] getLocalCertificates() {
+- return session.getLocalCertificates();
+- }
-
-- @Override
-- public ReferenceCountedOpenSslEngine get(long ssl) {
-- return engines.get(ssl);
-- }
-- }
+- @Override
+- public javax.security.cert.X509Certificate[] getPeerCertificateChain()
+- throws SSLPeerUnverifiedException {
+- return session.getPeerCertificateChain();
+- }
-
-- static void setKeyMaterial(long ctx, X509Certificate[] keyCertChain, PrivateKey key, String keyPassword)
-- throws SSLException {
-- /* Load the certificate file and private key. */
-- long keyBio = 0;
-- long keyCertChainBio = 0;
-- long keyCertChainBio2 = 0;
-- PemEncoded encoded = null;
-- try {
-- // Only encode one time
-- encoded = PemX509Certificate.toPEM(ByteBufAllocator.DEFAULT, true, keyCertChain);
-- keyCertChainBio = toBIO(ByteBufAllocator.DEFAULT, encoded.retain());
-- keyCertChainBio2 = toBIO(ByteBufAllocator.DEFAULT, encoded.retain());
+- @Override
+- public Principal getPeerPrincipal() throws SSLPeerUnverifiedException {
+- return session.getPeerPrincipal();
+- }
-
-- if (key != null) {
-- keyBio = toBIO(key);
-- }
+- @Override
+- public Principal getLocalPrincipal() {
+- return session.getLocalPrincipal();
+- }
-
-- SSLContext.setCertificateBio(
-- ctx, keyCertChainBio, keyBio,
-- keyPassword == null ? StringUtil.EMPTY_STRING : keyPassword);
-- // We may have more then one cert in the chain so add all of them now.
-- SSLContext.setCertificateChainBio(ctx, keyCertChainBio2, true);
-- } catch (SSLException e) {
-- throw e;
-- } catch (Exception e) {
-- throw new SSLException("failed to set certificate and key", e);
-- } finally {
-- freeBio(keyBio);
-- freeBio(keyCertChainBio);
-- freeBio(keyCertChainBio2);
-- if (encoded != null) {
-- encoded.release();
-- }
-- }
-- }
+- @Override
+- public String getCipherSuite() {
+- return session.getCipherSuite();
+- }
-
-- static void freeBio(long bio) {
-- if (bio != 0) {
-- SSL.freeBIO(bio);
-- }
-- }
+- @Override
+- public String getProtocol() {
+- return SslUtils.PROTOCOL_TLS_V1_2;
+- }
-
-- /**
-- * Return the pointer to a <a href="https://www.openssl.org/docs/crypto/BIO_get_mem_ptr.html">in-memory BIO</a>
-- * or {@code 0} if the {@code key} is {@code null}. The BIO contains the content of the {@code key}.
-- */
-- static long toBIO(PrivateKey key) throws Exception {
-- if (key == null) {
-- return 0;
-- }
+- @Override
+- public String getPeerHost() {
+- return session.getPeerHost();
+- }
-
-- ByteBufAllocator allocator = ByteBufAllocator.DEFAULT;
-- PemEncoded pem = PemPrivateKey.toPEM(allocator, true, key);
-- try {
-- return toBIO(allocator, pem.retain());
-- } finally {
-- pem.release();
-- }
-- }
+- @Override
+- public int getPeerPort() {
+- return session.getPeerPort();
+- }
-
-- /**
-- * Return the pointer to a <a href="https://www.openssl.org/docs/crypto/BIO_get_mem_ptr.html">in-memory BIO</a>
-- * or {@code 0} if the {@code certChain} is {@code null}. The BIO contains the content of the {@code certChain}.
-- */
-- static long toBIO(X509Certificate... certChain) throws Exception {
-- if (certChain == null) {
-- return 0;
-- }
+- @Override
+- public int getPacketBufferSize() {
+- return session.getPacketBufferSize();
+- }
-
-- if (certChain.length == 0) {
-- throw new IllegalArgumentException("certChain can't be empty");
+- @Override
+- public int getApplicationBufferSize() {
+- return session.getApplicationBufferSize();
+- }
+- };
+- }
+- }
+- };
- }
+- return engine;
+- }
-
-- ByteBufAllocator allocator = ByteBufAllocator.DEFAULT;
-- PemEncoded pem = PemX509Certificate.toPEM(allocator, true, certChain);
-- try {
-- return toBIO(allocator, pem.retain());
-- } finally {
-- pem.release();
-- }
+- @Override
+- public void checkClientTrusted(X509Certificate[] x509Certificates, final String s, SSLEngine sslEngine)
+- throws CertificateException {
+- tm.checkClientTrusted(x509Certificates, s, wrapEngine(sslEngine));
- }
-
-- static long toBIO(ByteBufAllocator allocator, PemEncoded pem) throws Exception {
-- try {
-- // We can turn direct buffers straight into BIOs. No need to
-- // make a yet another copy.
-- ByteBuf content = pem.content();
+- @Override
+- public void checkServerTrusted(X509Certificate[] x509Certificates, String s, SSLEngine sslEngine)
+- throws CertificateException {
+- tm.checkServerTrusted(x509Certificates, s, wrapEngine(sslEngine));
+- }
-
-- if (content.isDirect()) {
-- return newBIO(content.retainedSlice());
-- }
+- @Override
+- public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
+- tm.checkClientTrusted(x509Certificates, s);
+- }
-
-- ByteBuf buffer = allocator.directBuffer(content.readableBytes());
-- try {
-- buffer.writeBytes(content, content.readerIndex(), content.readableBytes());
-- return newBIO(buffer.retainedSlice());
-- } finally {
-- try {
-- // If the contents of the ByteBuf is sensitive (e.g. a PrivateKey) we
-- // need to zero out the bytes of the copy before we're releasing it.
-- if (pem.isSensitive()) {
-- SslUtils.zeroout(buffer);
-- }
-- } finally {
-- buffer.release();
-- }
-- }
-- } finally {
-- pem.release();
-- }
+- @Override
+- public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
+- tm.checkServerTrusted(x509Certificates, s);
- }
-
-- private static long newBIO(ByteBuf buffer) throws Exception {
-- try {
-- long bio = SSL.newMemBIO();
-- int readable = buffer.readableBytes();
-- if (SSL.bioWrite(bio, OpenSsl.memoryAddress(buffer) + buffer.readerIndex(), readable) != readable) {
-- SSL.freeBIO(bio);
-- throw new IllegalStateException("Could not write data to memory BIO");
-- }
-- return bio;
-- } finally {
-- buffer.release();
-- }
+- @Override
+- public X509Certificate[] getAcceptedIssuers() {
+- return tm.getAcceptedIssuers();
- }
-}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngine.java b/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngine.java
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslX509KeyManagerFactory.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslX509KeyManagerFactory.java
deleted file mode 100644
-index 27460c7..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngine.java
+index 2a86332fe1..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslX509KeyManagerFactory.java
+++ /dev/null
-@@ -1,2037 +0,0 @@
+@@ -1,413 +0,0 @@
-/*
-- * Copyright 2016 The Netty Project
+- * Copyright 2018 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
@@ -3485,4638 +3793,4204 @@ index 27460c7..0000000
- */
-package io.netty.handler.ssl;
-
--import io.netty.buffer.ByteBuf;
-import io.netty.buffer.ByteBufAllocator;
--import io.netty.internal.tcnative.Buffer;
+-import io.netty.buffer.UnpooledByteBufAllocator;
-import io.netty.internal.tcnative.SSL;
--import io.netty.util.AbstractReferenceCounted;
--import io.netty.util.ReferenceCounted;
--import io.netty.util.ResourceLeakDetector;
--import io.netty.util.ResourceLeakDetectorFactory;
--import io.netty.util.ResourceLeakTracker;
--import io.netty.util.internal.EmptyArrays;
--import io.netty.util.internal.PlatformDependent;
--import io.netty.util.internal.StringUtil;
--import io.netty.util.internal.ThrowableUtil;
--import io.netty.util.internal.UnstableApi;
--import io.netty.util.internal.logging.InternalLogger;
--import io.netty.util.internal.logging.InternalLoggerFactory;
+-import io.netty.util.ReferenceCountUtil;
+-import io.netty.util.internal.ObjectUtil;
-
--import java.nio.ByteBuffer;
--import java.nio.ReadOnlyBufferException;
--import java.security.Principal;
+-import javax.net.ssl.KeyManager;
+-import javax.net.ssl.KeyManagerFactory;
+-import javax.net.ssl.KeyManagerFactorySpi;
+-import javax.net.ssl.ManagerFactoryParameters;
+-import javax.net.ssl.X509KeyManager;
+-import java.io.File;
+-import java.io.IOException;
+-import java.io.InputStream;
+-import java.io.OutputStream;
+-import java.security.InvalidAlgorithmParameterException;
+-import java.security.Key;
+-import java.security.KeyStore;
+-import java.security.KeyStoreException;
+-import java.security.KeyStoreSpi;
+-import java.security.NoSuchAlgorithmException;
+-import java.security.PrivateKey;
+-import java.security.Provider;
+-import java.security.UnrecoverableKeyException;
-import java.security.cert.Certificate;
--import java.util.ArrayList;
--import java.util.Arrays;
--import java.util.Collection;
+-import java.security.cert.CertificateException;
+-import java.security.cert.X509Certificate;
+-import java.util.Collections;
+-import java.util.Date;
+-import java.util.Enumeration;
-import java.util.HashMap;
--import java.util.List;
-import java.util.Map;
--import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
--
--import java.util.concurrent.locks.Lock;
--import javax.net.ssl.SSLEngine;
--import javax.net.ssl.SSLEngineResult;
--import javax.net.ssl.SSLException;
--import javax.net.ssl.SSLHandshakeException;
--import javax.net.ssl.SSLParameters;
--import javax.net.ssl.SSLPeerUnverifiedException;
--import javax.net.ssl.SSLSession;
--import javax.net.ssl.SSLSessionBindingEvent;
--import javax.net.ssl.SSLSessionBindingListener;
--import javax.net.ssl.SSLSessionContext;
--import javax.security.cert.X509Certificate;
--
--import static io.netty.handler.ssl.OpenSsl.memoryAddress;
--import static io.netty.handler.ssl.SslUtils.SSL_RECORD_HEADER_LENGTH;
--import static io.netty.util.internal.EmptyArrays.EMPTY_CERTIFICATES;
--import static io.netty.util.internal.EmptyArrays.EMPTY_JAVAX_X509_CERTIFICATES;
--import static io.netty.util.internal.ObjectUtil.checkNotNull;
--import static java.lang.Math.min;
--import static javax.net.ssl.SSLEngineResult.HandshakeStatus.FINISHED;
--import static javax.net.ssl.SSLEngineResult.HandshakeStatus.NEED_UNWRAP;
--import static javax.net.ssl.SSLEngineResult.HandshakeStatus.NEED_WRAP;
--import static javax.net.ssl.SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING;
--import static javax.net.ssl.SSLEngineResult.Status.BUFFER_OVERFLOW;
--import static javax.net.ssl.SSLEngineResult.Status.BUFFER_UNDERFLOW;
--import static javax.net.ssl.SSLEngineResult.Status.CLOSED;
--import static javax.net.ssl.SSLEngineResult.Status.OK;
-
-/**
-- * Implements a {@link SSLEngine} using
-- * <a href="https://www.openssl.org/docs/crypto/BIO_s_bio.html#EXAMPLE">OpenSSL BIO abstractions</a>.
-- * <p>Instances of this class must be {@link #release() released} or else native memory will leak!
+- * Special {@link KeyManagerFactory} that pre-compute the keymaterial used when {@link SslProvider#OPENSSL} or
+- * {@link SslProvider#OPENSSL_REFCNT} is used and so will improve handshake times and its performance.
- *
-- * <p>Instances of this class <strong>must</strong> be released before the {@link ReferenceCountedOpenSslContext}
-- * the instance depends upon are released. Otherwise if any method of this class is called which uses the
-- * the {@link ReferenceCountedOpenSslContext} JNI resources the JVM may crash.
-- */
--public class ReferenceCountedOpenSslEngine extends SSLEngine implements ReferenceCounted {
--
-- private static final InternalLogger logger = InternalLoggerFactory.getInstance(ReferenceCountedOpenSslEngine.class);
--
-- private static final SSLException BEGIN_HANDSHAKE_ENGINE_CLOSED = ThrowableUtil.unknownStackTrace(
-- new SSLException("engine closed"), ReferenceCountedOpenSslEngine.class, "beginHandshake()");
-- private static final SSLException HANDSHAKE_ENGINE_CLOSED = ThrowableUtil.unknownStackTrace(
-- new SSLException("engine closed"), ReferenceCountedOpenSslEngine.class, "handshake()");
-- private static final SSLException RENEGOTIATION_UNSUPPORTED = ThrowableUtil.unknownStackTrace(
-- new SSLException("renegotiation unsupported"), ReferenceCountedOpenSslEngine.class, "beginHandshake()");
-- private static final ResourceLeakDetector<ReferenceCountedOpenSslEngine> leakDetector =
-- ResourceLeakDetectorFactory.instance().newResourceLeakDetector(ReferenceCountedOpenSslEngine.class);
-- /**
-- * <a href="https://www.openssl.org/docs/man1.0.2/crypto/X509_check_host.html">The flags argument is usually 0</a>.
-- */
-- private static final int DEFAULT_HOSTNAME_VALIDATION_FLAGS = 0;
+- *
+- *
+- * Because the keymaterial is pre-computed any modification to the {@link KeyStore} is ignored after
+- * {@link #init(KeyStore, char[])} is called.
+- *
+- * {@link #init(ManagerFactoryParameters)} is not supported by this implementation and so a call to it will always
+- * result in an {@link InvalidAlgorithmParameterException}.
+- */
+-public final class OpenSslX509KeyManagerFactory extends KeyManagerFactory {
-
-- static final int MAX_PLAINTEXT_LENGTH = 16 * 1024; // 2^14
+- private final OpenSslKeyManagerFactorySpi spi;
-
-- /**
-- * This is the maximum overhead when encrypting plaintext as defined by
-- * <a href="https://www.ietf.org/rfc/rfc5246.txt">rfc5264</a>,
-- * <a href="https://www.ietf.org/rfc/rfc5289.txt">rfc5289</a> and openssl implementation itself.
-- *
-- * Please note that we use a padding of 16 here as openssl uses PKC#5 which uses 16 bytes while the spec itself
-- * allow up to 255 bytes. 16 bytes is the max for PKC#5 (which handles it the same way as PKC#7) as we use a block
-- * size of 16. See <a href="https://tools.ietf.org/html/rfc5652#section-6.3">rfc5652#section-6.3</a>.
-- *
-- * TLS Header (5) + 16 (IV) + 48 (MAC) + 1 (Padding_length field) + 15 (Padding) + 1 (ContentType) +
-- * 2 (ProtocolVersion) + 2 (Length)
-- *
-- * TODO: We may need to review this calculation once TLS 1.3 becomes available.
-- */
-- static final int MAX_TLS_RECORD_OVERHEAD_LENGTH = SSL_RECORD_HEADER_LENGTH + 16 + 48 + 1 + 15 + 1 + 2 + 2;
+- public OpenSslX509KeyManagerFactory() {
+- this(newOpenSslKeyManagerFactorySpi(null));
+- }
-
-- static final int MAX_ENCRYPTED_PACKET_LENGTH = MAX_PLAINTEXT_LENGTH + MAX_TLS_RECORD_OVERHEAD_LENGTH;
+- public OpenSslX509KeyManagerFactory(Provider provider) {
+- this(newOpenSslKeyManagerFactorySpi(provider));
+- }
-
-- private static final AtomicIntegerFieldUpdater<ReferenceCountedOpenSslEngine> DESTROYED_UPDATER =
-- AtomicIntegerFieldUpdater.newUpdater(ReferenceCountedOpenSslEngine.class, "destroyed");
+- public OpenSslX509KeyManagerFactory(String algorithm, Provider provider) throws NoSuchAlgorithmException {
+- this(newOpenSslKeyManagerFactorySpi(algorithm, provider));
+- }
-
-- private static final String INVALID_CIPHER = "SSL_NULL_WITH_NULL_NULL";
-- private static final SSLEngineResult NEED_UNWRAP_OK = new SSLEngineResult(OK, NEED_UNWRAP, 0, 0);
-- private static final SSLEngineResult NEED_UNWRAP_CLOSED = new SSLEngineResult(CLOSED, NEED_UNWRAP, 0, 0);
-- private static final SSLEngineResult NEED_WRAP_OK = new SSLEngineResult(OK, NEED_WRAP, 0, 0);
-- private static final SSLEngineResult NEED_WRAP_CLOSED = new SSLEngineResult(CLOSED, NEED_WRAP, 0, 0);
-- private static final SSLEngineResult CLOSED_NOT_HANDSHAKING = new SSLEngineResult(CLOSED, NOT_HANDSHAKING, 0, 0);
+- private OpenSslX509KeyManagerFactory(OpenSslKeyManagerFactorySpi spi) {
+- super(spi, spi.kmf.getProvider(), spi.kmf.getAlgorithm());
+- this.spi = spi;
+- }
-
-- // OpenSSL state
-- private long ssl;
-- private long networkBIO;
-- private boolean certificateSet;
+- private static OpenSslKeyManagerFactorySpi newOpenSslKeyManagerFactorySpi(Provider provider) {
+- try {
+- return newOpenSslKeyManagerFactorySpi(null, provider);
+- } catch (NoSuchAlgorithmException e) {
+- // This should never happen as we use the default algorithm.
+- throw new IllegalStateException(e);
+- }
+- }
-
-- private enum HandshakeState {
-- /**
-- * Not started yet.
-- */
-- NOT_STARTED,
-- /**
-- * Started via unwrap/wrap.
-- */
-- STARTED_IMPLICITLY,
-- /**
-- * Started via {@link #beginHandshake()}.
-- */
-- STARTED_EXPLICITLY,
+- private static OpenSslKeyManagerFactorySpi newOpenSslKeyManagerFactorySpi(String algorithm, Provider provider)
+- throws NoSuchAlgorithmException {
+- if (algorithm == null) {
+- algorithm = KeyManagerFactory.getDefaultAlgorithm();
+- }
+- return new OpenSslKeyManagerFactorySpi(
+- provider == null ? KeyManagerFactory.getInstance(algorithm) :
+- KeyManagerFactory.getInstance(algorithm, provider));
+- }
-
-- /**
-- * Handshake is finished.
-- */
-- FINISHED
+- OpenSslKeyMaterialProvider newProvider() {
+- return spi.newProvider();
- }
-
-- private HandshakeState handshakeState = HandshakeState.NOT_STARTED;
-- private boolean renegotiationPending;
-- private boolean receivedShutdown;
-- private volatile int destroyed;
+- private static final class OpenSslKeyManagerFactorySpi extends KeyManagerFactorySpi {
+- final KeyManagerFactory kmf;
+- private volatile ProviderFactory providerFactory;
+-
+- OpenSslKeyManagerFactorySpi(KeyManagerFactory kmf) {
+- this.kmf = ObjectUtil.checkNotNull(kmf, "kmf");
+- }
-
-- // Reference Counting
-- private final ResourceLeakTracker<ReferenceCountedOpenSslEngine> leak;
-- private final AbstractReferenceCounted refCnt = new AbstractReferenceCounted() {
- @Override
-- public ReferenceCounted touch(Object hint) {
-- if (leak != null) {
-- leak.record(hint);
+- protected synchronized void engineInit(KeyStore keyStore, char[] chars)
+- throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
+- if (providerFactory != null) {
+- throw new KeyStoreException("Already initialized");
+- }
+- if (!keyStore.aliases().hasMoreElements()) {
+- throw new KeyStoreException("No aliases found");
- }
-
-- return ReferenceCountedOpenSslEngine.this;
+- kmf.init(keyStore, chars);
+- providerFactory = new ProviderFactory(ReferenceCountedOpenSslContext.chooseX509KeyManager(
+- kmf.getKeyManagers()), password(chars), Collections.list(keyStore.aliases()));
- }
-
-- @Override
-- protected void deallocate() {
-- shutdown();
-- if (leak != null) {
-- boolean closed = leak.close(ReferenceCountedOpenSslEngine.this);
-- assert closed;
+- private static String password(char[] password) {
+- if (password == null || password.length == 0) {
+- return null;
- }
+- return new String(password);
- }
-- };
-
-- private volatile ClientAuth clientAuth = ClientAuth.NONE;
+- @Override
+- protected void engineInit(ManagerFactoryParameters managerFactoryParameters)
+- throws InvalidAlgorithmParameterException {
+- throw new InvalidAlgorithmParameterException("Not supported");
+- }
-
-- // Updated once a new handshake is started and so the SSLSession reused.
-- private volatile long lastAccessed = -1;
+- @Override
+- protected KeyManager[] engineGetKeyManagers() {
+- ProviderFactory providerFactory = this.providerFactory;
+- if (providerFactory == null) {
+- throw new IllegalStateException("engineInit(...) not called yet");
+- }
+- return new KeyManager[] { providerFactory.keyManager };
+- }
-
-- private String endPointIdentificationAlgorithm;
-- // Store as object as AlgorithmConstraints only exists since java 7.
-- private Object algorithmConstraints;
-- private List<String> sniHostNames;
+- OpenSslKeyMaterialProvider newProvider() {
+- ProviderFactory providerFactory = this.providerFactory;
+- if (providerFactory == null) {
+- throw new IllegalStateException("engineInit(...) not called yet");
+- }
+- return providerFactory.newProvider();
+- }
-
-- // Mark as volatile as accessed by checkSniHostnameMatch(...) and also not specify the SNIMatcher type to allow us
-- // using it with java7.
-- private volatile Collection<?> matchers;
+- private static final class ProviderFactory {
+- private final X509KeyManager keyManager;
+- private final String password;
+- private final Iterable<String> aliases;
-
-- // SSL Engine status variables
-- private boolean isInboundDone;
-- private boolean outboundClosed;
+- ProviderFactory(X509KeyManager keyManager, String password, Iterable<String> aliases) {
+- this.keyManager = keyManager;
+- this.password = password;
+- this.aliases = aliases;
+- }
-
-- private final boolean clientMode;
-- private final ByteBufAllocator alloc;
-- private final OpenSslEngineMap engineMap;
-- private final OpenSslApplicationProtocolNegotiator apn;
-- private final boolean rejectRemoteInitiatedRenegotiation;
-- private final OpenSslSession session;
-- private final Certificate[] localCerts;
-- private final ByteBuffer[] singleSrcBuffer = new ByteBuffer[1];
-- private final ByteBuffer[] singleDstBuffer = new ByteBuffer[1];
-- private final OpenSslKeyMaterialManager keyMaterialManager;
-- private final boolean enableOcsp;
+- OpenSslKeyMaterialProvider newProvider() {
+- return new OpenSslPopulatedKeyMaterialProvider(keyManager,
+- password, aliases);
+- }
-
-- // This is package-private as we set it from OpenSslContext if an exception is thrown during
-- // the verification step.
-- SSLHandshakeException handshakeException;
+- /**
+- * {@link OpenSslKeyMaterialProvider} implementation that pre-compute the {@link OpenSslKeyMaterial} for
+- * all aliases.
+- */
+- private static final class OpenSslPopulatedKeyMaterialProvider extends OpenSslKeyMaterialProvider {
+- private final Map<String, Object> materialMap;
-
-- /**
-- * Create a new instance.
-- * @param context Reference count release responsibility is not transferred! The callee still owns this object.
-- * @param alloc The allocator to use.
-- * @param peerHost The peer host name.
-- * @param peerPort The peer port.
-- * @param leakDetection {@code true} to enable leak detection of this object.
-- */
-- ReferenceCountedOpenSslEngine(ReferenceCountedOpenSslContext context, ByteBufAllocator alloc, String peerHost,
-- int peerPort, boolean leakDetection) {
-- super(peerHost, peerPort);
-- OpenSsl.ensureAvailability();
-- leak = leakDetection ? leakDetector.track(this) : null;
-- this.alloc = checkNotNull(alloc, "alloc");
-- apn = (OpenSslApplicationProtocolNegotiator) context.applicationProtocolNegotiator();
-- session = new OpenSslSession(context.sessionContext());
-- clientMode = context.isClient();
-- engineMap = context.engineMap;
-- rejectRemoteInitiatedRenegotiation = context.getRejectRemoteInitiatedRenegotiation();
-- localCerts = context.keyCertChain;
-- keyMaterialManager = context.keyMaterialManager();
-- enableOcsp = context.enableOcsp;
+- OpenSslPopulatedKeyMaterialProvider(
+- X509KeyManager keyManager, String password, Iterable<String> aliases) {
+- super(keyManager, password);
+- materialMap = new HashMap<String, Object>();
+- boolean initComplete = false;
+- try {
+- for (String alias: aliases) {
+- if (alias != null && !materialMap.containsKey(alias)) {
+- try {
+- materialMap.put(alias, super.chooseKeyMaterial(
+- UnpooledByteBufAllocator.DEFAULT, alias));
+- } catch (Exception e) {
+- // Just store the exception and rethrow it when we try to choose the keymaterial
+- // for this alias later on.
+- materialMap.put(alias, e);
+- }
+- }
+- }
+- initComplete = true;
+- } finally {
+- if (!initComplete) {
+- destroy();
+- }
+- }
+- if (materialMap.isEmpty()) {
+- throw new IllegalArgumentException("aliases must be non-empty");
+- }
+- }
-
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
-- try {
-- ssl = SSL.newSSL(context.ctx, !context.isClient());
-- } finally {
-- readerLock.unlock();
+- @Override
+- OpenSslKeyMaterial chooseKeyMaterial(ByteBufAllocator allocator, String alias) throws Exception {
+- Object value = materialMap.get(alias);
+- if (value == null) {
+- // There is no keymaterial for the requested alias, return null
+- return null;
+- }
+- if (value instanceof OpenSslKeyMaterial) {
+- return ((OpenSslKeyMaterial) value).retain();
+- }
+- throw (Exception) value;
+- }
+-
+- @Override
+- void destroy() {
+- for (Object material: materialMap.values()) {
+- ReferenceCountUtil.release(material);
+- }
+- materialMap.clear();
+- }
+- }
- }
-- try {
-- networkBIO = SSL.bioNewByteBuffer(ssl, context.getBioNonApplicationBufferSize());
+- }
-
-- // Set the client auth mode, this needs to be done via setClientAuth(...) method so we actually call the
-- // needed JNI methods.
-- setClientAuth(clientMode ? ClientAuth.NONE : context.clientAuth);
+- /**
+- * Create a new initialized {@link OpenSslX509KeyManagerFactory} which loads its {@link PrivateKey} directly from
+- * an {@code OpenSSL engine} via the
+- * <a href="https://www.openssl.org/docs/man1.1.0/crypto/ENGINE_load_private_key.html">ENGINE_load_private_key</a>
+- * function.
+- */
+- public static OpenSslX509KeyManagerFactory newEngineBased(File certificateChain, String password)
+- throws CertificateException, IOException,
+- KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
+- return newEngineBased(SslContext.toX509Certificates(certificateChain), password);
+- }
-
-- if (context.protocols != null) {
-- setEnabledProtocols(context.protocols);
-- }
+- /**
+- * Create a new initialized {@link OpenSslX509KeyManagerFactory} which loads its {@link PrivateKey} directly from
+- * an {@code OpenSSL engine} via the
+- * <a href="https://www.openssl.org/docs/man1.1.0/crypto/ENGINE_load_private_key.html">ENGINE_load_private_key</a>
+- * function.
+- */
+- public static OpenSslX509KeyManagerFactory newEngineBased(X509Certificate[] certificateChain, String password)
+- throws CertificateException, IOException,
+- KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
+- KeyStore store = new OpenSslKeyStore(certificateChain.clone(), false);
+- store.load(null, null);
+- OpenSslX509KeyManagerFactory factory = new OpenSslX509KeyManagerFactory();
+- factory.init(store, password == null ? null : password.toCharArray());
+- return factory;
+- }
-
-- // Use SNI if peerHost was specified
-- // See https://github.com/netty/netty/issues/4746
-- if (clientMode && peerHost != null) {
-- SSL.setTlsExtHostName(ssl, peerHost);
-- }
+- /**
+- * See {@link OpenSslX509KeyManagerFactory#newEngineBased(X509Certificate[], String)}.
+- */
+- public static OpenSslX509KeyManagerFactory newKeyless(File chain)
+- throws CertificateException, IOException,
+- KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
+- return newKeyless(SslContext.toX509Certificates(chain));
+- }
-
-- if (enableOcsp) {
-- SSL.enableOcsp(ssl);
-- }
-- } catch (Throwable cause) {
-- SSL.freeSSL(ssl);
-- PlatformDependent.throwException(cause);
-- }
+- /**
+- * See {@link OpenSslX509KeyManagerFactory#newEngineBased(X509Certificate[], String)}.
+- */
+- public static OpenSslX509KeyManagerFactory newKeyless(InputStream chain)
+- throws CertificateException, IOException,
+- KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
+- return newKeyless(SslContext.toX509Certificates(chain));
- }
-
- /**
-- * Sets the OCSP response.
+- * Returns a new initialized {@link OpenSslX509KeyManagerFactory} which will provide its private key by using the
+- * {@link OpenSslPrivateKeyMethod}.
- */
-- @UnstableApi
-- public void setOcspResponse(byte[] response) {
-- if (!enableOcsp) {
-- throw new IllegalStateException("OCSP stapling is not enabled");
-- }
+- public static OpenSslX509KeyManagerFactory newKeyless(X509Certificate... certificateChain)
+- throws CertificateException, IOException,
+- KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
+- KeyStore store = new OpenSslKeyStore(certificateChain.clone(), true);
+- store.load(null, null);
+- OpenSslX509KeyManagerFactory factory = new OpenSslX509KeyManagerFactory();
+- factory.init(store, null);
+- return factory;
+- }
-
-- if (clientMode) {
-- throw new IllegalStateException("Not a server SSLEngine");
-- }
+- private static final class OpenSslKeyStore extends KeyStore {
+- private OpenSslKeyStore(final X509Certificate[] certificateChain, final boolean keyless) {
+- super(new KeyStoreSpi() {
-
-- synchronized (this) {
-- SSL.setOcspResponse(ssl, response);
+- private final Date creationDate = new Date();
+-
+- @Override
+- public Key engineGetKey(String alias, char[] password) throws UnrecoverableKeyException {
+- if (engineContainsAlias(alias)) {
+- final long privateKeyAddress;
+- if (keyless) {
+- privateKeyAddress = 0;
+- } else {
+- try {
+- privateKeyAddress = SSL.loadPrivateKeyFromEngine(
+- alias, password == null ? null : new String(password));
+- } catch (Exception e) {
+- UnrecoverableKeyException keyException =
+- new UnrecoverableKeyException("Unable to load key from engine");
+- keyException.initCause(e);
+- throw keyException;
+- }
+- }
+- return new OpenSslPrivateKey(privateKeyAddress);
+- }
+- return null;
+- }
+-
+- @Override
+- public Certificate[] engineGetCertificateChain(String alias) {
+- return engineContainsAlias(alias)? certificateChain.clone() : null;
+- }
+-
+- @Override
+- public Certificate engineGetCertificate(String alias) {
+- return engineContainsAlias(alias)? certificateChain[0] : null;
+- }
+-
+- @Override
+- public Date engineGetCreationDate(String alias) {
+- return engineContainsAlias(alias)? creationDate : null;
+- }
+-
+- @Override
+- public void engineSetKeyEntry(String alias, Key key, char[] password, Certificate[] chain)
+- throws KeyStoreException {
+- throw new KeyStoreException("Not supported");
+- }
+-
+- @Override
+- public void engineSetKeyEntry(String alias, byte[] key, Certificate[] chain) throws KeyStoreException {
+- throw new KeyStoreException("Not supported");
+- }
+-
+- @Override
+- public void engineSetCertificateEntry(String alias, Certificate cert) throws KeyStoreException {
+- throw new KeyStoreException("Not supported");
+- }
+-
+- @Override
+- public void engineDeleteEntry(String alias) throws KeyStoreException {
+- throw new KeyStoreException("Not supported");
+- }
+-
+- @Override
+- public Enumeration<String> engineAliases() {
+- return Collections.enumeration(Collections.singleton(SslContext.ALIAS));
+- }
+-
+- @Override
+- public boolean engineContainsAlias(String alias) {
+- return SslContext.ALIAS.equals(alias);
+- }
+-
+- @Override
+- public int engineSize() {
+- return 1;
+- }
+-
+- @Override
+- public boolean engineIsKeyEntry(String alias) {
+- return engineContainsAlias(alias);
+- }
+-
+- @Override
+- public boolean engineIsCertificateEntry(String alias) {
+- return engineContainsAlias(alias);
+- }
+-
+- @Override
+- public String engineGetCertificateAlias(Certificate cert) {
+- if (cert instanceof X509Certificate) {
+- for (X509Certificate x509Certificate : certificateChain) {
+- if (x509Certificate.equals(cert)) {
+- return SslContext.ALIAS;
+- }
+- }
+- }
+- return null;
+- }
+-
+- @Override
+- public void engineStore(OutputStream stream, char[] password) {
+- throw new UnsupportedOperationException();
+- }
+-
+- @Override
+- public void engineLoad(InputStream stream, char[] password) {
+- if (stream != null && password != null) {
+- throw new UnsupportedOperationException();
+- }
+- }
+- }, null, "native");
+-
+- OpenSsl.ensureAvailability();
- }
- }
+-}
+diff --git a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslClientContext.java b/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslClientContext.java
+deleted file mode 100644
+index 6b945506b9..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslClientContext.java
++++ /dev/null
+@@ -1,343 +0,0 @@
+-/*
+- * Copyright 2016 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- * http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-package io.netty.handler.ssl;
+-
+-import io.netty.internal.tcnative.CertificateCallback;
+-import io.netty.util.internal.SuppressJava6Requirement;
+-import io.netty.util.internal.SystemPropertyUtil;
+-import io.netty.util.internal.logging.InternalLogger;
+-import io.netty.util.internal.logging.InternalLoggerFactory;
+-import io.netty.internal.tcnative.SSL;
+-import io.netty.internal.tcnative.SSLContext;
+-
+-import java.security.KeyStore;
+-import java.security.PrivateKey;
+-import java.security.cert.X509Certificate;
+-
+-import java.util.Arrays;
+-import java.util.Collections;
+-import java.util.HashSet;
+-import java.util.LinkedHashSet;
+-import java.util.Set;
-
-- /**
-- * Returns the OCSP response or {@code null} if the server didn't provide a stapled OCSP response.
-- */
-- @UnstableApi
-- public byte[] getOcspResponse() {
-- if (!enableOcsp) {
-- throw new IllegalStateException("OCSP stapling is not enabled");
-- }
+-import javax.net.ssl.KeyManagerFactory;
+-import javax.net.ssl.SSLException;
+-import javax.net.ssl.TrustManagerFactory;
+-import javax.net.ssl.X509ExtendedTrustManager;
+-import javax.net.ssl.X509TrustManager;
+-import javax.security.auth.x500.X500Principal;
-
-- if (!clientMode) {
-- throw new IllegalStateException("Not a client SSLEngine");
-- }
+-/**
+- * A client-side {@link SslContext} which uses OpenSSL's SSL/TLS implementation.
+- * <p>Instances of this class must be {@link #release() released} or else native memory will leak!
+- *
+- * <p>Instances of this class <strong>must not</strong> be released before any {@link ReferenceCountedOpenSslEngine}
+- * which depends upon the instance of this class is released. Otherwise if any method of
+- * {@link ReferenceCountedOpenSslEngine} is called which uses this class's JNI resources the JVM may crash.
+- */
+-public final class ReferenceCountedOpenSslClientContext extends ReferenceCountedOpenSslContext {
+- private static final InternalLogger logger =
+- InternalLoggerFactory.getInstance(ReferenceCountedOpenSslClientContext.class);
+- private static final Set<String> SUPPORTED_KEY_TYPES = Collections.unmodifiableSet(new LinkedHashSet<String>(
+- Arrays.asList(OpenSslKeyMaterialManager.KEY_TYPE_RSA,
+- OpenSslKeyMaterialManager.KEY_TYPE_DH_RSA,
+- OpenSslKeyMaterialManager.KEY_TYPE_EC,
+- OpenSslKeyMaterialManager.KEY_TYPE_EC_RSA,
+- OpenSslKeyMaterialManager.KEY_TYPE_EC_EC)));
+- private static final boolean ENABLE_SESSION_TICKET =
+- SystemPropertyUtil.getBoolean("jdk.tls.client.enableSessionTicketExtension", false);
+- private final OpenSslSessionContext sessionContext;
-
-- synchronized (this) {
-- return SSL.getOcspResponse(ssl);
+- ReferenceCountedOpenSslClientContext(X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory,
+- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword,
+- KeyManagerFactory keyManagerFactory, Iterable<String> ciphers,
+- CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
+- String[] protocols, long sessionCacheSize, long sessionTimeout,
+- boolean enableOcsp, String keyStore) throws SSLException {
+- super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, SSL.SSL_MODE_CLIENT, keyCertChain,
+- ClientAuth.NONE, protocols, false, enableOcsp, true);
+- boolean success = false;
+- try {
+- sessionContext = newSessionContext(this, ctx, engineMap, trustCertCollection, trustManagerFactory,
+- keyCertChain, key, keyPassword, keyManagerFactory, keyStore);
+- if (ENABLE_SESSION_TICKET) {
+- sessionContext.setTicketKeys();
+- }
+- success = true;
+- } finally {
+- if (!success) {
+- release();
+- }
- }
- }
-
- @Override
-- public final int refCnt() {
-- return refCnt.refCnt();
-- }
--
-- @Override
-- public final ReferenceCounted retain() {
-- refCnt.retain();
-- return this;
+- public OpenSslSessionContext sessionContext() {
+- return sessionContext;
- }
-
-- @Override
-- public final ReferenceCounted retain(int increment) {
-- refCnt.retain(increment);
-- return this;
-- }
+- static OpenSslSessionContext newSessionContext(ReferenceCountedOpenSslContext thiz, long ctx,
+- OpenSslEngineMap engineMap,
+- X509Certificate[] trustCertCollection,
+- TrustManagerFactory trustManagerFactory,
+- X509Certificate[] keyCertChain, PrivateKey key,
+- String keyPassword, KeyManagerFactory keyManagerFactory,
+- String keyStore) throws SSLException {
+- if (key == null && keyCertChain != null || key != null && keyCertChain == null) {
+- throw new IllegalArgumentException(
+- "Either both keyCertChain and key needs to be null or none of them");
+- }
+- OpenSslKeyMaterialProvider keyMaterialProvider = null;
+- try {
+- try {
+- if (!OpenSsl.useKeyManagerFactory()) {
+- if (keyManagerFactory != null) {
+- throw new IllegalArgumentException(
+- "KeyManagerFactory not supported");
+- }
+- if (keyCertChain != null/* && key != null*/) {
+- setKeyMaterial(ctx, keyCertChain, key, keyPassword);
+- }
+- } else {
+- // javadocs state that keyManagerFactory has precedent over keyCertChain
+- if (keyManagerFactory == null && keyCertChain != null) {
+- char[] keyPasswordChars = keyStorePassword(keyPassword);
+- KeyStore ks = buildKeyStore(keyCertChain, key, keyPasswordChars, keyStore);
+- if (ks.aliases().hasMoreElements()) {
+- keyManagerFactory = new OpenSslX509KeyManagerFactory();
+- } else {
+- keyManagerFactory = new OpenSslCachingX509KeyManagerFactory(
+- KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()));
+- }
+- keyManagerFactory.init(ks, keyPasswordChars);
+- keyMaterialProvider = providerFor(keyManagerFactory, keyPassword);
+- } else if (keyManagerFactory != null) {
+- keyMaterialProvider = providerFor(keyManagerFactory, keyPassword);
+- }
-
-- @Override
-- public final ReferenceCounted touch() {
-- refCnt.touch();
-- return this;
-- }
+- if (keyMaterialProvider != null) {
+- OpenSslKeyMaterialManager materialManager = new OpenSslKeyMaterialManager(keyMaterialProvider);
+- SSLContext.setCertificateCallback(ctx, new OpenSslClientCertificateCallback(
+- engineMap, materialManager));
+- }
+- }
+- } catch (Exception e) {
+- throw new SSLException("failed to set certificate and key", e);
+- }
-
-- @Override
-- public final ReferenceCounted touch(Object hint) {
-- refCnt.touch(hint);
-- return this;
-- }
+- // On the client side we always need to use SSL_CVERIFY_OPTIONAL (which will translate to SSL_VERIFY_PEER)
+- // to ensure that when the TrustManager throws we will produce the correct alert back to the server.
+- //
+- // See:
+- // - https://www.openssl.org/docs/man1.0.2/man3/SSL_CTX_set_verify.html
+- // - https://github.com/netty/netty/issues/8942
+- SSLContext.setVerify(ctx, SSL.SSL_CVERIFY_OPTIONAL, VERIFY_DEPTH);
-
-- @Override
-- public final boolean release() {
-- return refCnt.release();
-- }
+- try {
+- if (trustCertCollection != null) {
+- trustManagerFactory = buildTrustManagerFactory(trustCertCollection, trustManagerFactory, keyStore);
+- } else if (trustManagerFactory == null) {
+- trustManagerFactory = TrustManagerFactory.getInstance(
+- TrustManagerFactory.getDefaultAlgorithm());
+- trustManagerFactory.init((KeyStore) null);
+- }
+- final X509TrustManager manager = chooseTrustManager(trustManagerFactory.getTrustManagers());
-
-- @Override
-- public final boolean release(int decrement) {
-- return refCnt.release(decrement);
-- }
+- // IMPORTANT: The callbacks set for verification must be static to prevent memory leak as
+- // otherwise the context can never be collected. This is because the JNI code holds
+- // a global reference to the callbacks.
+- //
+- // See https://github.com/netty/netty/issues/5372
-
-- @Override
-- public final synchronized SSLSession getHandshakeSession() {
-- // Javadocs state return value should be:
-- // null if this instance is not currently handshaking, or if the current handshake has not
-- // progressed far enough to create a basic SSLSession. Otherwise, this method returns the
-- // SSLSession currently being negotiated.
-- switch(handshakeState) {
-- case NOT_STARTED:
-- case FINISHED:
-- return null;
-- default:
-- return session;
+- setVerifyCallback(ctx, engineMap, manager);
+- } catch (Exception e) {
+- if (keyMaterialProvider != null) {
+- keyMaterialProvider.destroy();
+- }
+- throw new SSLException("unable to setup trustmanager", e);
+- }
+- OpenSslClientSessionContext context = new OpenSslClientSessionContext(thiz, keyMaterialProvider);
+- keyMaterialProvider = null;
+- return context;
+- } finally {
+- if (keyMaterialProvider != null) {
+- keyMaterialProvider.destroy();
+- }
- }
- }
-
-- /**
-- * Returns the pointer to the {@code SSL} object for this {@link ReferenceCountedOpenSslEngine}.
-- * Be aware that it is freed as soon as the {@link #release()} or {@link #shutdown()} methods are called.
-- * At this point {@code 0} will be returned.
-- */
-- public final synchronized long sslPointer() {
-- return ssl;
+- @SuppressJava6Requirement(reason = "Guarded by java version check")
+- private static void setVerifyCallback(long ctx, OpenSslEngineMap engineMap, X509TrustManager manager) {
+- // Use this to prevent an error when running on java < 7
+- if (useExtendedTrustManager(manager)) {
+- SSLContext.setCertVerifyCallback(ctx,
+- new ExtendedTrustManagerVerifyCallback(engineMap, (X509ExtendedTrustManager) manager));
+- } else {
+- SSLContext.setCertVerifyCallback(ctx, new TrustManagerVerifyCallback(engineMap, manager));
+- }
- }
-
-- /**
-- * Destroys this engine.
-- */
-- public final synchronized void shutdown() {
-- if (DESTROYED_UPDATER.compareAndSet(this, 0, 1)) {
-- engineMap.remove(ssl);
-- SSL.freeSSL(ssl);
-- ssl = networkBIO = 0;
--
-- isInboundDone = outboundClosed = true;
+- // No cache is currently supported for client side mode.
+- static final class OpenSslClientSessionContext extends OpenSslSessionContext {
+- OpenSslClientSessionContext(ReferenceCountedOpenSslContext context, OpenSslKeyMaterialProvider provider) {
+- super(context, provider);
- }
-
-- // On shutdown clear all errors
-- SSL.clearError();
-- }
+- @Override
+- public void setSessionTimeout(int seconds) {
+- if (seconds < 0) {
+- throw new IllegalArgumentException();
+- }
+- }
-
-- /**
-- * Write plaintext data to the OpenSSL internal BIO
-- *
-- * Calling this function with src.remaining == 0 is undefined.
-- */
-- private int writePlaintextData(final ByteBuffer src, int len) {
-- final int pos = src.position();
-- final int limit = src.limit();
-- final int sslWrote;
+- @Override
+- public int getSessionTimeout() {
+- return 0;
+- }
-
-- if (src.isDirect()) {
-- sslWrote = SSL.writeToSSL(ssl, Buffer.address(src) + pos, len);
-- if (sslWrote > 0) {
-- src.position(pos + sslWrote);
+- @Override
+- public void setSessionCacheSize(int size) {
+- if (size < 0) {
+- throw new IllegalArgumentException();
- }
-- } else {
-- ByteBuf buf = alloc.directBuffer(len);
-- try {
-- src.limit(pos + len);
+- }
-
-- buf.setBytes(0, src);
-- src.limit(limit);
+- @Override
+- public int getSessionCacheSize() {
+- return 0;
+- }
-
-- sslWrote = SSL.writeToSSL(ssl, memoryAddress(buf), len);
-- if (sslWrote > 0) {
-- src.position(pos + sslWrote);
-- } else {
-- src.position(pos);
-- }
-- } finally {
-- buf.release();
-- }
+- @Override
+- public void setSessionCacheEnabled(boolean enabled) {
+- // ignored
+- }
+-
+- @Override
+- public boolean isSessionCacheEnabled() {
+- return false;
- }
-- return sslWrote;
- }
-
-- /**
-- * Write encrypted data to the OpenSSL network BIO.
-- */
-- private ByteBuf writeEncryptedData(final ByteBuffer src, int len) {
-- final int pos = src.position();
-- if (src.isDirect()) {
-- SSL.bioSetByteBuffer(networkBIO, Buffer.address(src) + pos, len, false);
-- } else {
-- final ByteBuf buf = alloc.directBuffer(len);
-- try {
-- final int limit = src.limit();
-- src.limit(pos + len);
-- buf.writeBytes(src);
-- // Restore the original position and limit because we don't want to consume from `src`.
-- src.position(pos);
-- src.limit(limit);
+- private static final class TrustManagerVerifyCallback extends AbstractCertificateVerifier {
+- private final X509TrustManager manager;
-
-- SSL.bioSetByteBuffer(networkBIO, memoryAddress(buf), len, false);
-- return buf;
-- } catch (Throwable cause) {
-- buf.release();
-- PlatformDependent.throwException(cause);
-- }
+- TrustManagerVerifyCallback(OpenSslEngineMap engineMap, X509TrustManager manager) {
+- super(engineMap);
+- this.manager = manager;
- }
-- return null;
-- }
-
-- /**
-- * Read plaintext data from the OpenSSL internal BIO
-- */
-- private int readPlaintextData(final ByteBuffer dst) {
-- final int sslRead;
-- final int pos = dst.position();
-- if (dst.isDirect()) {
-- sslRead = SSL.readFromSSL(ssl, Buffer.address(dst) + pos, dst.limit() - pos);
-- if (sslRead > 0) {
-- dst.position(pos + sslRead);
-- }
-- } else {
-- final int limit = dst.limit();
-- final int len = min(MAX_ENCRYPTED_PACKET_LENGTH, limit - pos);
-- final ByteBuf buf = alloc.directBuffer(len);
-- try {
-- sslRead = SSL.readFromSSL(ssl, memoryAddress(buf), len);
-- if (sslRead > 0) {
-- dst.limit(pos + sslRead);
-- buf.getBytes(buf.readerIndex(), dst);
-- dst.limit(limit);
-- }
-- } finally {
-- buf.release();
-- }
+- @Override
+- void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts, String auth)
+- throws Exception {
+- manager.checkServerTrusted(peerCerts, auth);
- }
--
-- return sslRead;
- }
-
-- @Override
-- public final SSLEngineResult wrap(
-- final ByteBuffer[] srcs, int offset, final int length, final ByteBuffer dst) throws SSLException {
-- // Throw required runtime exceptions
-- if (srcs == null) {
-- throw new IllegalArgumentException("srcs is null");
-- }
-- if (dst == null) {
-- throw new IllegalArgumentException("dst is null");
+- @SuppressJava6Requirement(reason = "Usage guarded by java version check")
+- private static final class ExtendedTrustManagerVerifyCallback extends AbstractCertificateVerifier {
+- private final X509ExtendedTrustManager manager;
+-
+- ExtendedTrustManagerVerifyCallback(OpenSslEngineMap engineMap, X509ExtendedTrustManager manager) {
+- super(engineMap);
+- this.manager = OpenSslTlsv13X509ExtendedTrustManager.wrap(manager);
- }
-
-- if (offset >= srcs.length || offset + length > srcs.length) {
-- throw new IndexOutOfBoundsException(
-- "offset: " + offset + ", length: " + length +
-- " (expected: offset <= offset + length <= srcs.length (" + srcs.length + "))");
+- @Override
+- void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts, String auth)
+- throws Exception {
+- manager.checkServerTrusted(peerCerts, auth, engine);
- }
+- }
-
-- if (dst.isReadOnly()) {
-- throw new ReadOnlyBufferException();
+- private static final class OpenSslClientCertificateCallback implements CertificateCallback {
+- private final OpenSslEngineMap engineMap;
+- private final OpenSslKeyMaterialManager keyManagerHolder;
+-
+- OpenSslClientCertificateCallback(OpenSslEngineMap engineMap, OpenSslKeyMaterialManager keyManagerHolder) {
+- this.engineMap = engineMap;
+- this.keyManagerHolder = keyManagerHolder;
- }
-
-- synchronized (this) {
-- if (isOutboundDone()) {
-- // All drained in the outbound buffer
-- return isInboundDone() || isDestroyed() ? CLOSED_NOT_HANDSHAKING : NEED_UNWRAP_CLOSED;
+- @Override
+- public void handle(long ssl, byte[] keyTypeBytes, byte[][] asn1DerEncodedPrincipals) throws Exception {
+- final ReferenceCountedOpenSslEngine engine = engineMap.get(ssl);
+- // May be null if it was destroyed in the meantime.
+- if (engine == null) {
+- return;
- }
--
-- int bytesProduced = 0;
-- ByteBuf bioReadCopyBuf = null;
- try {
-- // Setup the BIO buffer so that we directly write the encryption results into dst.
-- if (dst.isDirect()) {
-- SSL.bioSetByteBuffer(networkBIO, Buffer.address(dst) + dst.position(), dst.remaining(),
-- true);
+- final Set<String> keyTypesSet = supportedClientKeyTypes(keyTypeBytes);
+- final String[] keyTypes = keyTypesSet.toArray(new String[0]);
+- final X500Principal[] issuers;
+- if (asn1DerEncodedPrincipals == null) {
+- issuers = null;
- } else {
-- bioReadCopyBuf = alloc.directBuffer(dst.remaining());
-- SSL.bioSetByteBuffer(networkBIO, memoryAddress(bioReadCopyBuf), bioReadCopyBuf.writableBytes(),
-- true);
-- }
--
-- int bioLengthBefore = SSL.bioLengthByteBuffer(networkBIO);
--
-- // Explicit use outboundClosed as we want to drain any bytes that are still present.
-- if (outboundClosed) {
-- // There is something left to drain.
-- // See https://github.com/netty/netty/issues/6260
-- bytesProduced = SSL.bioFlushByteBuffer(networkBIO);
-- if (bytesProduced <= 0) {
-- return newResultMayFinishHandshake(NOT_HANDSHAKING, 0, 0);
-- }
-- // It is possible when the outbound was closed there was not enough room in the non-application
-- // buffers to hold the close_notify. We should keep trying to close until we consume all the data
-- // OpenSSL can give us.
-- if (!doSSLShutdown()) {
-- return newResultMayFinishHandshake(NOT_HANDSHAKING, 0, bytesProduced);
+- issuers = new X500Principal[asn1DerEncodedPrincipals.length];
+- for (int i = 0; i < asn1DerEncodedPrincipals.length; i++) {
+- issuers[i] = new X500Principal(asn1DerEncodedPrincipals[i]);
- }
-- bytesProduced = bioLengthBefore - SSL.bioLengthByteBuffer(networkBIO);
-- return newResultMayFinishHandshake(NEED_WRAP, 0, bytesProduced);
- }
+- keyManagerHolder.setKeyMaterialClientSide(engine, keyTypes, issuers);
+- } catch (Throwable cause) {
+- logger.debug("request of key failed", cause);
+- engine.initHandshakeException(cause);
+- }
+- }
-
-- // Flush any data that may be implicitly generated by OpenSSL (handshake, close, etc..).
-- SSLEngineResult.HandshakeStatus status = NOT_HANDSHAKING;
-- // Prepare OpenSSL to work in server mode and receive handshake
-- if (handshakeState != HandshakeState.FINISHED) {
-- if (handshakeState != HandshakeState.STARTED_EXPLICITLY) {
-- // Update accepted so we know we triggered the handshake via wrap
-- handshakeState = HandshakeState.STARTED_IMPLICITLY;
-- }
--
-- // Flush any data that may have been written implicitly during the handshake by OpenSSL.
-- bytesProduced = SSL.bioFlushByteBuffer(networkBIO);
--
-- if (bytesProduced > 0 && handshakeException != null) {
-- // TODO(scott): It is possible that when the handshake failed there was not enough room in the
-- // non-application buffers to hold the alert. We should get all the data before progressing on.
-- // However I'm not aware of a way to do this with the OpenSSL APIs.
-- // See https://github.com/netty/netty/issues/6385.
--
-- // We produced / consumed some data during the handshake, signal back to the caller.
-- // If there is a handshake exception and we have produced data, we should send the data before
-- // we allow handshake() to throw the handshake exception.
-- return newResult(NEED_WRAP, 0, bytesProduced);
-- }
--
-- status = handshake();
+- /**
+- * Gets the supported key types for client certificates.
+- *
+- * @param clientCertificateTypes {@code ClientCertificateType} values provided by the server.
+- * See https://www.ietf.org/assignments/tls-parameters/tls-parameters.xml.
+- * @return supported key types that can be used in {@code X509KeyManager.chooseClientAlias} and
+- * {@code X509ExtendedKeyManager.chooseEngineClientAlias}.
+- */
+- private static Set<String> supportedClientKeyTypes(byte[] clientCertificateTypes) {
+- if (clientCertificateTypes == null) {
+- // Try all of the supported key types.
+- return SUPPORTED_KEY_TYPES;
+- }
+- Set<String> result = new HashSet<String>(clientCertificateTypes.length);
+- for (byte keyTypeCode : clientCertificateTypes) {
+- String keyType = clientKeyType(keyTypeCode);
+- if (keyType == null) {
+- // Unsupported client key type -- ignore
+- continue;
+- }
+- result.add(keyType);
+- }
+- return result;
+- }
-
-- if (renegotiationPending && status == FINISHED) {
-- // If renegotiationPending is true that means when we attempted to start renegotiation
-- // the BIO buffer didn't have enough space to hold the HelloRequest which prompts the
-- // client to initiate a renegotiation. At this point the HelloRequest has been written
-- // so we can actually start the handshake process.
-- renegotiationPending = false;
-- SSL.setState(ssl, SSL.SSL_ST_ACCEPT);
-- handshakeState = HandshakeState.STARTED_EXPLICITLY;
-- status = handshake();
-- }
+- private static String clientKeyType(byte clientCertificateType) {
+- // See also http://www.ietf.org/assignments/tls-parameters/tls-parameters.xml
+- switch (clientCertificateType) {
+- case CertificateCallback.TLS_CT_RSA_SIGN:
+- return OpenSslKeyMaterialManager.KEY_TYPE_RSA; // RFC rsa_sign
+- case CertificateCallback.TLS_CT_RSA_FIXED_DH:
+- return OpenSslKeyMaterialManager.KEY_TYPE_DH_RSA; // RFC rsa_fixed_dh
+- case CertificateCallback.TLS_CT_ECDSA_SIGN:
+- return OpenSslKeyMaterialManager.KEY_TYPE_EC; // RFC ecdsa_sign
+- case CertificateCallback.TLS_CT_RSA_FIXED_ECDH:
+- return OpenSslKeyMaterialManager.KEY_TYPE_EC_RSA; // RFC rsa_fixed_ecdh
+- case CertificateCallback.TLS_CT_ECDSA_FIXED_ECDH:
+- return OpenSslKeyMaterialManager.KEY_TYPE_EC_EC; // RFC ecdsa_fixed_ecdh
+- default:
+- return null;
+- }
+- }
+- }
+-}
+diff --git a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslContext.java b/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslContext.java
+deleted file mode 100644
+index 27eb43574c..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslContext.java
++++ /dev/null
+@@ -1,968 +0,0 @@
+-/*
+- * Copyright 2016 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- * http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-package io.netty.handler.ssl;
-
-- // Handshake may have generated more data, for example if the internal SSL buffer is small
-- // we may have freed up space by flushing above.
-- bytesProduced = bioLengthBefore - SSL.bioLengthByteBuffer(networkBIO);
+-import io.netty.buffer.ByteBuf;
+-import io.netty.buffer.ByteBufAllocator;
+-import io.netty.internal.tcnative.CertificateVerifier;
+-import io.netty.internal.tcnative.SSL;
+-import io.netty.internal.tcnative.SSLContext;
+-import io.netty.internal.tcnative.SSLPrivateKeyMethod;
+-import io.netty.util.AbstractReferenceCounted;
+-import io.netty.util.ReferenceCounted;
+-import io.netty.util.ResourceLeakDetector;
+-import io.netty.util.ResourceLeakDetectorFactory;
+-import io.netty.util.ResourceLeakTracker;
+-import io.netty.util.internal.ObjectUtil;
+-import io.netty.util.internal.PlatformDependent;
+-import io.netty.util.internal.StringUtil;
+-import io.netty.util.internal.SuppressJava6Requirement;
+-import io.netty.util.internal.SystemPropertyUtil;
+-import io.netty.util.internal.UnstableApi;
+-import io.netty.util.internal.logging.InternalLogger;
+-import io.netty.util.internal.logging.InternalLoggerFactory;
-
-- if (bytesProduced > 0) {
-- // If we have filled up the dst buffer and we have not finished the handshake we should try to
-- // wrap again. Otherwise we should only try to wrap again if there is still data pending in
-- // SSL buffers.
-- return newResult(mayFinishHandshake(status != FINISHED ?
-- bytesProduced == bioLengthBefore ? NEED_WRAP :
-- getHandshakeStatus(SSL.bioLengthNonApplication(networkBIO)) : FINISHED),
-- 0, bytesProduced);
-- }
+-import java.security.PrivateKey;
+-import java.security.SignatureException;
+-import java.security.cert.CertPathValidatorException;
+-import java.security.cert.Certificate;
+-import java.security.cert.CertificateExpiredException;
+-import java.security.cert.CertificateNotYetValidException;
+-import java.security.cert.CertificateRevokedException;
+-import java.security.cert.X509Certificate;
+-import java.util.Arrays;
+-import java.util.Collections;
+-import java.util.List;
+-import java.util.Map;
+-import java.util.concurrent.Executor;
+-import java.util.concurrent.locks.Lock;
+-import java.util.concurrent.locks.ReadWriteLock;
+-import java.util.concurrent.locks.ReentrantReadWriteLock;
-
-- if (status == NEED_UNWRAP) {
-- // Signal if the outbound is done or not.
-- return isOutboundDone() ? NEED_UNWRAP_CLOSED : NEED_UNWRAP_OK;
-- }
+-import javax.net.ssl.KeyManager;
+-import javax.net.ssl.KeyManagerFactory;
+-import javax.net.ssl.SSLEngine;
+-import javax.net.ssl.SSLException;
+-import javax.net.ssl.SSLHandshakeException;
+-import javax.net.ssl.TrustManager;
+-import javax.net.ssl.X509ExtendedTrustManager;
+-import javax.net.ssl.X509KeyManager;
+-import javax.net.ssl.X509TrustManager;
-
-- // Explicit use outboundClosed and not outboundClosed() as we want to drain any bytes that are
-- // still present.
-- if (outboundClosed) {
-- bytesProduced = SSL.bioFlushByteBuffer(networkBIO);
-- return newResultMayFinishHandshake(status, 0, bytesProduced);
-- }
-- }
+-import static io.netty.handler.ssl.OpenSsl.DEFAULT_CIPHERS;
+-import static io.netty.handler.ssl.OpenSsl.availableJavaCipherSuites;
+-import static io.netty.util.internal.ObjectUtil.checkNotNull;
+-import static io.netty.util.internal.ObjectUtil.checkPositiveOrZero;
-
-- int srcsLen = 0;
-- final int endOffset = offset + length;
-- for (int i = offset; i < endOffset; ++i) {
-- final ByteBuffer src = srcs[i];
-- if (src == null) {
-- throw new IllegalArgumentException("srcs[" + i + "] is null");
-- }
-- if (srcsLen == MAX_PLAINTEXT_LENGTH) {
-- continue;
-- }
+-/**
+- * An implementation of {@link SslContext} which works with libraries that support the
+- * <a href="https://www.openssl.org/">OpenSsl</a> C library API.
+- * <p>Instances of this class must be {@link #release() released} or else native memory will leak!
+- *
+- * <p>Instances of this class <strong>must not</strong> be released before any {@link ReferenceCountedOpenSslEngine}
+- * which depends upon the instance of this class is released. Otherwise if any method of
+- * {@link ReferenceCountedOpenSslEngine} is called which uses this class's JNI resources the JVM may crash.
+- */
+-public abstract class ReferenceCountedOpenSslContext extends SslContext implements ReferenceCounted {
+- private static final InternalLogger logger =
+- InternalLoggerFactory.getInstance(ReferenceCountedOpenSslContext.class);
-
-- srcsLen += src.remaining();
-- if (srcsLen > MAX_PLAINTEXT_LENGTH || srcsLen < 0) {
-- // If srcLen > MAX_PLAINTEXT_LENGTH or secLen < 0 just set it to MAX_PLAINTEXT_LENGTH.
-- // This also help us to guard against overflow.
-- // We not break out here as we still need to check for null entries in srcs[].
-- srcsLen = MAX_PLAINTEXT_LENGTH;
-- }
-- }
+- private static final int DEFAULT_BIO_NON_APPLICATION_BUFFER_SIZE = Math.max(1,
+- SystemPropertyUtil.getInt("io.netty.handler.ssl.openssl.bioNonApplicationBufferSize",
+- 2048));
+- static final boolean USE_TASKS =
+- SystemPropertyUtil.getBoolean("io.netty.handler.ssl.openssl.useTasks", false);
+- private static final Integer DH_KEY_LENGTH;
+- private static final ResourceLeakDetector<ReferenceCountedOpenSslContext> leakDetector =
+- ResourceLeakDetectorFactory.instance().newResourceLeakDetector(ReferenceCountedOpenSslContext.class);
-
-- // we will only produce a single TLS packet, and we don't aggregate src buffers,
-- // so we always fix the number of buffers to 1 when checking if the dst buffer is large enough.
-- if (dst.remaining() < calculateOutNetBufSize(srcsLen, 1)) {
-- return new SSLEngineResult(BUFFER_OVERFLOW, getHandshakeStatus(), 0, 0);
-- }
+- // TODO: Maybe make configurable ?
+- protected static final int VERIFY_DEPTH = 10;
-
-- // There was no pending data in the network BIO -- encrypt any application data
-- int bytesConsumed = 0;
-- // Flush any data that may have been written implicitly by OpenSSL in case a shutdown/alert occurs.
-- bytesProduced = SSL.bioFlushByteBuffer(networkBIO);
-- for (; offset < endOffset; ++offset) {
-- final ByteBuffer src = srcs[offset];
-- final int remaining = src.remaining();
-- if (remaining == 0) {
-- continue;
-- }
+- /**
+- * The OpenSSL SSL_CTX object.
+- *
+- * <strong>{@link #ctxLock} must be hold while using ctx!</strong>
+- */
+- protected long ctx;
+- private final List<String> unmodifiableCiphers;
+- private final long sessionCacheSize;
+- private final long sessionTimeout;
+- private final OpenSslApplicationProtocolNegotiator apn;
+- private final int mode;
-
-- // Write plaintext application data to the SSL engine
-- int bytesWritten = writePlaintextData(src, min(remaining, MAX_PLAINTEXT_LENGTH - bytesConsumed));
+- // Reference Counting
+- private final ResourceLeakTracker<ReferenceCountedOpenSslContext> leak;
+- private final AbstractReferenceCounted refCnt = new AbstractReferenceCounted() {
+- @Override
+- public ReferenceCounted touch(Object hint) {
+- if (leak != null) {
+- leak.record(hint);
+- }
-
-- if (bytesWritten > 0) {
-- bytesConsumed += bytesWritten;
+- return ReferenceCountedOpenSslContext.this;
+- }
-
-- // Determine how much encrypted data was generated:
-- final int pendingNow = SSL.bioLengthByteBuffer(networkBIO);
-- bytesProduced += bioLengthBefore - pendingNow;
-- bioLengthBefore = pendingNow;
+- @Override
+- protected void deallocate() {
+- destroy();
+- if (leak != null) {
+- boolean closed = leak.close(ReferenceCountedOpenSslContext.this);
+- assert closed;
+- }
+- }
+- };
-
-- return newResultMayFinishHandshake(status, bytesConsumed, bytesProduced);
-- } else {
-- int sslError = SSL.getError(ssl, bytesWritten);
-- if (sslError == SSL.SSL_ERROR_ZERO_RETURN) {
-- // This means the connection was shutdown correctly, close inbound and outbound
-- if (!receivedShutdown) {
-- closeAll();
+- final Certificate[] keyCertChain;
+- final ClientAuth clientAuth;
+- final String[] protocols;
+- final boolean enableOcsp;
+- final OpenSslEngineMap engineMap = new DefaultOpenSslEngineMap();
+- final ReadWriteLock ctxLock = new ReentrantReadWriteLock();
-
-- bytesProduced += bioLengthBefore - SSL.bioLengthByteBuffer(networkBIO);
+- private volatile int bioNonApplicationBufferSize = DEFAULT_BIO_NON_APPLICATION_BUFFER_SIZE;
-
-- // If we have filled up the dst buffer and we have not finished the handshake we should
-- // try to wrap again. Otherwise we should only try to wrap again if there is still data
-- // pending in SSL buffers.
-- SSLEngineResult.HandshakeStatus hs = mayFinishHandshake(
-- status != FINISHED ? bytesProduced == dst.remaining() ? NEED_WRAP
-- : getHandshakeStatus(SSL.bioLengthNonApplication(networkBIO))
-- : FINISHED);
-- return newResult(hs, bytesConsumed, bytesProduced);
-- }
+- @SuppressWarnings("deprecation")
+- static final OpenSslApplicationProtocolNegotiator NONE_PROTOCOL_NEGOTIATOR =
+- new OpenSslApplicationProtocolNegotiator() {
+- @Override
+- public ApplicationProtocolConfig.Protocol protocol() {
+- return ApplicationProtocolConfig.Protocol.NONE;
+- }
-
-- return newResult(NOT_HANDSHAKING, bytesConsumed, bytesProduced);
-- } else if (sslError == SSL.SSL_ERROR_WANT_READ) {
-- // If there is no pending data to read from BIO we should go back to event loop and try
-- // to read more data [1]. It is also possible that event loop will detect the socket has
-- // been closed. [1] https://www.openssl.org/docs/manmaster/ssl/SSL_write.html
-- return newResult(NEED_UNWRAP, bytesConsumed, bytesProduced);
-- } else if (sslError == SSL.SSL_ERROR_WANT_WRITE) {
-- // SSL_ERROR_WANT_WRITE typically means that the underlying transport is not writable
-- // and we should set the "want write" flag on the selector and try again when the
-- // underlying transport is writable [1]. However we are not directly writing to the
-- // underlying transport and instead writing to a BIO buffer. The OpenSsl documentation
-- // says we should do the following [1]:
-- //
-- // "When using a buffering BIO, like a BIO pair, data must be written into or retrieved
-- // out of the BIO before being able to continue."
-- //
-- // So we attempt to drain the BIO buffer below, but if there is no data this condition
-- // is undefined and we assume their is a fatal error with the openssl engine and close.
-- // [1] https://www.openssl.org/docs/manmaster/ssl/SSL_write.html
-- return newResult(NEED_WRAP, bytesConsumed, bytesProduced);
-- } else {
-- // Everything else is considered as error
-- throw shutdownWithError("SSL_write");
-- }
-- }
+- @Override
+- public List<String> protocols() {
+- return Collections.emptyList();
- }
-- return newResultMayFinishHandshake(status, bytesConsumed, bytesProduced);
-- } finally {
-- SSL.bioClearByteBuffer(networkBIO);
-- if (bioReadCopyBuf == null) {
-- dst.position(dst.position() + bytesProduced);
-- } else {
-- assert bioReadCopyBuf.readableBytes() <= dst.remaining() : "The destination buffer " + dst +
-- " didn't have enough remaining space to hold the encrypted content in " + bioReadCopyBuf;
-- dst.put(bioReadCopyBuf.internalNioBuffer(bioReadCopyBuf.readerIndex(), bytesProduced));
-- bioReadCopyBuf.release();
+-
+- @Override
+- public ApplicationProtocolConfig.SelectorFailureBehavior selectorFailureBehavior() {
+- return ApplicationProtocolConfig.SelectorFailureBehavior.CHOOSE_MY_LAST_PROTOCOL;
- }
-- }
-- }
-- }
-
-- private SSLEngineResult newResult(SSLEngineResult.HandshakeStatus hs, int bytesConsumed, int bytesProduced) {
-- return newResult(OK, hs, bytesConsumed, bytesProduced);
-- }
+- @Override
+- public ApplicationProtocolConfig.SelectedListenerFailureBehavior selectedListenerFailureBehavior() {
+- return ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT;
+- }
+- };
-
-- private SSLEngineResult newResult(SSLEngineResult.Status status, SSLEngineResult.HandshakeStatus hs,
-- int bytesConsumed, int bytesProduced) {
-- // If isOutboundDone, then the data from the network BIO
-- // was the close_notify message and all was consumed we are not required to wait
-- // for the receipt the peer's close_notify message -- shutdown.
-- if (isOutboundDone()) {
-- if (isInboundDone()) {
-- // If the inbound was done as well, we need to ensure we return NOT_HANDSHAKING to signal we are done.
-- hs = NOT_HANDSHAKING;
+- static {
+- Integer dhLen = null;
-
-- // As the inbound and the outbound is done we can shutdown the engine now.
-- shutdown();
+- try {
+- String dhKeySize = SystemPropertyUtil.get("jdk.tls.ephemeralDHKeySize");
+- if (dhKeySize != null) {
+- try {
+- dhLen = Integer.valueOf(dhKeySize);
+- } catch (NumberFormatException e) {
+- logger.debug("ReferenceCountedOpenSslContext supports -Djdk.tls.ephemeralDHKeySize={int}, but got: "
+- + dhKeySize);
+- }
- }
-- return new SSLEngineResult(CLOSED, hs, bytesConsumed, bytesProduced);
+- } catch (Throwable ignore) {
+- // ignore
- }
-- return new SSLEngineResult(status, hs, bytesConsumed, bytesProduced);
+- DH_KEY_LENGTH = dhLen;
- }
-
-- private SSLEngineResult newResultMayFinishHandshake(SSLEngineResult.HandshakeStatus hs,
-- int bytesConsumed, int bytesProduced) throws SSLException {
-- return newResult(mayFinishHandshake(hs != FINISHED ? getHandshakeStatus() : FINISHED),
-- bytesConsumed, bytesProduced);
+- ReferenceCountedOpenSslContext(Iterable<String> ciphers, CipherSuiteFilter cipherFilter,
+- ApplicationProtocolConfig apnCfg, long sessionCacheSize, long sessionTimeout,
+- int mode, Certificate[] keyCertChain, ClientAuth clientAuth, String[] protocols,
+- boolean startTls, boolean enableOcsp, boolean leakDetection) throws SSLException {
+- this(ciphers, cipherFilter, toNegotiator(apnCfg), sessionCacheSize, sessionTimeout, mode, keyCertChain,
+- clientAuth, protocols, startTls, enableOcsp, leakDetection);
- }
-
-- private SSLEngineResult newResultMayFinishHandshake(SSLEngineResult.Status status,
-- SSLEngineResult.HandshakeStatus hs,
-- int bytesConsumed, int bytesProduced) throws SSLException {
-- return newResult(status, mayFinishHandshake(hs != FINISHED ? getHandshakeStatus() : FINISHED),
-- bytesConsumed, bytesProduced);
-- }
+- ReferenceCountedOpenSslContext(Iterable<String> ciphers, CipherSuiteFilter cipherFilter,
+- OpenSslApplicationProtocolNegotiator apn, long sessionCacheSize,
+- long sessionTimeout, int mode, Certificate[] keyCertChain,
+- ClientAuth clientAuth, String[] protocols, boolean startTls, boolean enableOcsp,
+- boolean leakDetection) throws SSLException {
+- super(startTls);
-
-- /**
-- * Log the error, shutdown the engine and throw an exception.
-- */
-- private SSLException shutdownWithError(String operations) {
-- String err = SSL.getLastError();
-- return shutdownWithError(operations, err);
-- }
+- OpenSsl.ensureAvailability();
-
-- private SSLException shutdownWithError(String operation, String err) {
-- if (logger.isDebugEnabled()) {
-- logger.debug("{} failed: OpenSSL error: {}", operation, err);
+- if (enableOcsp && !OpenSsl.isOcspSupported()) {
+- throw new IllegalStateException("OCSP is not supported.");
- }
-
-- // There was an internal error -- shutdown
-- shutdown();
-- if (handshakeState == HandshakeState.FINISHED) {
-- return new SSLException(err);
+- if (mode != SSL.SSL_MODE_SERVER && mode != SSL.SSL_MODE_CLIENT) {
+- throw new IllegalArgumentException("mode most be either SSL.SSL_MODE_SERVER or SSL.SSL_MODE_CLIENT");
- }
-- return new SSLHandshakeException(err);
-- }
+- leak = leakDetection ? leakDetector.track(this) : null;
+- this.mode = mode;
+- this.clientAuth = isServer() ? checkNotNull(clientAuth, "clientAuth") : ClientAuth.NONE;
+- this.protocols = protocols;
+- this.enableOcsp = enableOcsp;
-
-- public final SSLEngineResult unwrap(
-- final ByteBuffer[] srcs, int srcsOffset, final int srcsLength,
-- final ByteBuffer[] dsts, int dstsOffset, final int dstsLength) throws SSLException {
+- this.keyCertChain = keyCertChain == null ? null : keyCertChain.clone();
-
-- // Throw required runtime exceptions
-- if (srcs == null) {
-- throw new NullPointerException("srcs");
-- }
-- if (srcsOffset >= srcs.length
-- || srcsOffset + srcsLength > srcs.length) {
-- throw new IndexOutOfBoundsException(
-- "offset: " + srcsOffset + ", length: " + srcsLength +
-- " (expected: offset <= offset + length <= srcs.length (" + srcs.length + "))");
-- }
-- if (dsts == null) {
-- throw new IllegalArgumentException("dsts is null");
-- }
-- if (dstsOffset >= dsts.length || dstsOffset + dstsLength > dsts.length) {
-- throw new IndexOutOfBoundsException(
-- "offset: " + dstsOffset + ", length: " + dstsLength +
-- " (expected: offset <= offset + length <= dsts.length (" + dsts.length + "))");
-- }
-- long capacity = 0;
-- final int dstsEndOffset = dstsOffset + dstsLength;
-- for (int i = dstsOffset; i < dstsEndOffset; i ++) {
-- ByteBuffer dst = dsts[i];
-- if (dst == null) {
-- throw new IllegalArgumentException("dsts[" + i + "] is null");
-- }
-- if (dst.isReadOnly()) {
-- throw new ReadOnlyBufferException();
+- unmodifiableCiphers = Arrays.asList(checkNotNull(cipherFilter, "cipherFilter").filterCipherSuites(
+- ciphers, DEFAULT_CIPHERS, availableJavaCipherSuites()));
+-
+- this.apn = checkNotNull(apn, "apn");
+-
+- // Create a new SSL_CTX and configure it.
+- boolean success = false;
+- try {
+- try {
+- int protocolOpts = SSL.SSL_PROTOCOL_SSLV3 | SSL.SSL_PROTOCOL_TLSV1 |
+- SSL.SSL_PROTOCOL_TLSV1_1 | SSL.SSL_PROTOCOL_TLSV1_2;
+- if (OpenSsl.isTlsv13Supported()) {
+- protocolOpts |= SSL.SSL_PROTOCOL_TLSV1_3;
+- }
+- ctx = SSLContext.make(protocolOpts, mode);
+- } catch (Exception e) {
+- throw new SSLException("failed to create an SSL_CTX", e);
- }
-- capacity += dst.remaining();
-- }
-
-- final int srcsEndOffset = srcsOffset + srcsLength;
-- long len = 0;
-- for (int i = srcsOffset; i < srcsEndOffset; i++) {
-- ByteBuffer src = srcs[i];
-- if (src == null) {
-- throw new IllegalArgumentException("srcs[" + i + "] is null");
+- boolean tlsv13Supported = OpenSsl.isTlsv13Supported();
+- StringBuilder cipherBuilder = new StringBuilder();
+- StringBuilder cipherTLSv13Builder = new StringBuilder();
+-
+- /* List the ciphers that are permitted to negotiate. */
+- try {
+- if (unmodifiableCiphers.isEmpty()) {
+- // Set non TLSv1.3 ciphers.
+- SSLContext.setCipherSuite(ctx, StringUtil.EMPTY_STRING, false);
+- if (tlsv13Supported) {
+- // Set TLSv1.3 ciphers.
+- SSLContext.setCipherSuite(ctx, StringUtil.EMPTY_STRING, true);
+- }
+- } else {
+- CipherSuiteConverter.convertToCipherStrings(
+- unmodifiableCiphers, cipherBuilder, cipherTLSv13Builder, OpenSsl.isBoringSSL());
+-
+- // Set non TLSv1.3 ciphers.
+- SSLContext.setCipherSuite(ctx, cipherBuilder.toString(), false);
+- if (tlsv13Supported) {
+- // Set TLSv1.3 ciphers.
+- SSLContext.setCipherSuite(ctx, cipherTLSv13Builder.toString(), true);
+- }
+- }
+- } catch (SSLException e) {
+- throw e;
+- } catch (Exception e) {
+- throw new SSLException("failed to set cipher suite: " + unmodifiableCiphers, e);
- }
-- len += src.remaining();
-- }
-
-- synchronized (this) {
-- if (isInboundDone()) {
-- return isOutboundDone() || isDestroyed() ? CLOSED_NOT_HANDSHAKING : NEED_WRAP_CLOSED;
+- int options = SSLContext.getOptions(ctx) |
+- SSL.SSL_OP_NO_SSLv2 |
+- SSL.SSL_OP_NO_SSLv3 |
+- // Disable TLSv1.3 by default for now. Even if TLSv1.3 is not supported this will
+- // work fine as in this case SSL_OP_NO_TLSv1_3 will be 0.
+- SSL.SSL_OP_NO_TLSv1_3 |
+-
+- SSL.SSL_OP_CIPHER_SERVER_PREFERENCE |
+-
+- // We do not support compression at the moment so we should explicitly disable it.
+- SSL.SSL_OP_NO_COMPRESSION |
+-
+- // Disable ticket support by default to be more inline with SSLEngineImpl of the JDK.
+- // This also let SSLSession.getId() work the same way for the JDK implementation and the
+- // OpenSSLEngine. If tickets are supported SSLSession.getId() will only return an ID on the
+- // server-side if it could make use of tickets.
+- SSL.SSL_OP_NO_TICKET;
+-
+- if (cipherBuilder.length() == 0) {
+- // No ciphers that are compatible with SSLv2 / SSLv3 / TLSv1 / TLSv1.1 / TLSv1.2
+- options |= SSL.SSL_OP_NO_SSLv2 | SSL.SSL_OP_NO_SSLv3 | SSL.SSL_OP_NO_TLSv1
+- | SSL.SSL_OP_NO_TLSv1_1 | SSL.SSL_OP_NO_TLSv1_2;
- }
-
-- SSLEngineResult.HandshakeStatus status = NOT_HANDSHAKING;
-- // Prepare OpenSSL to work in server mode and receive handshake
-- if (handshakeState != HandshakeState.FINISHED) {
-- if (handshakeState != HandshakeState.STARTED_EXPLICITLY) {
-- // Update accepted so we know we triggered the handshake via wrap
-- handshakeState = HandshakeState.STARTED_IMPLICITLY;
-- }
+- SSLContext.setOptions(ctx, options);
+-
+- // We need to enable SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER as the memory address may change between
+- // calling OpenSSLEngine.wrap(...).
+- // See https://github.com/netty/netty-tcnative/issues/100
+- SSLContext.setMode(ctx, SSLContext.getMode(ctx) | SSL.SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
-
-- status = handshake();
-- if (status == NEED_WRAP) {
-- return NEED_WRAP_OK;
-- }
-- // Check if the inbound is considered to be closed if so let us try to wrap again.
-- if (isInboundDone) {
-- return NEED_WRAP_CLOSED;
-- }
+- if (DH_KEY_LENGTH != null) {
+- SSLContext.setTmpDHLength(ctx, DH_KEY_LENGTH);
- }
-
-- if (len < SSL_RECORD_HEADER_LENGTH) {
-- return newResultMayFinishHandshake(BUFFER_UNDERFLOW, status, 0, 0);
+- List<String> nextProtoList = apn.protocols();
+- /* Set next protocols for next protocol negotiation extension, if specified */
+- if (!nextProtoList.isEmpty()) {
+- String[] appProtocols = nextProtoList.toArray(new String[0]);
+- int selectorBehavior = opensslSelectorFailureBehavior(apn.selectorFailureBehavior());
+-
+- switch (apn.protocol()) {
+- case NPN:
+- SSLContext.setNpnProtos(ctx, appProtocols, selectorBehavior);
+- break;
+- case ALPN:
+- SSLContext.setAlpnProtos(ctx, appProtocols, selectorBehavior);
+- break;
+- case NPN_AND_ALPN:
+- SSLContext.setNpnProtos(ctx, appProtocols, selectorBehavior);
+- SSLContext.setAlpnProtos(ctx, appProtocols, selectorBehavior);
+- break;
+- default:
+- throw new Error();
+- }
- }
-
-- int packetLength = SslUtils.getEncryptedPacketLength(srcs, srcsOffset);
+- /* Set session cache size, if specified */
+- if (sessionCacheSize <= 0) {
+- // Get the default session cache size using SSLContext.setSessionCacheSize()
+- sessionCacheSize = SSLContext.setSessionCacheSize(ctx, 20480);
+- }
+- this.sessionCacheSize = sessionCacheSize;
+- SSLContext.setSessionCacheSize(ctx, sessionCacheSize);
-
-- if (packetLength == SslUtils.NOT_ENCRYPTED) {
-- throw new NotSslRecordException("not an SSL/TLS record");
+- /* Set session timeout, if specified */
+- if (sessionTimeout <= 0) {
+- // Get the default session timeout using SSLContext.setSessionCacheTimeout()
+- sessionTimeout = SSLContext.setSessionCacheTimeout(ctx, 300);
- }
+- this.sessionTimeout = sessionTimeout;
+- SSLContext.setSessionCacheTimeout(ctx, sessionTimeout);
-
-- if (packetLength - SSL_RECORD_HEADER_LENGTH > capacity) {
-- // No enough space in the destination buffer so signal the caller
-- // that the buffer needs to be increased.
-- return newResultMayFinishHandshake(BUFFER_OVERFLOW, status, 0, 0);
+- if (enableOcsp) {
+- SSLContext.enableOcsp(ctx, isClient());
- }
-
-- if (len < packetLength) {
-- // We either have no enough data to read the packet length at all or not enough for reading
-- // the whole packet.
-- return newResultMayFinishHandshake(BUFFER_UNDERFLOW, status, 0, 0);
+- SSLContext.setUseTasks(ctx, USE_TASKS);
+- success = true;
+- } finally {
+- if (!success) {
+- release();
- }
+- }
+- }
-
-- // This must always be the case when we reached here as if not we returned BUFFER_UNDERFLOW.
-- assert srcsOffset < srcsEndOffset;
+- private static int opensslSelectorFailureBehavior(ApplicationProtocolConfig.SelectorFailureBehavior behavior) {
+- switch (behavior) {
+- case NO_ADVERTISE:
+- return SSL.SSL_SELECTOR_FAILURE_NO_ADVERTISE;
+- case CHOOSE_MY_LAST_PROTOCOL:
+- return SSL.SSL_SELECTOR_FAILURE_CHOOSE_MY_LAST_PROTOCOL;
+- default:
+- throw new Error();
+- }
+- }
-
-- // This must always be the case if we reached here.
-- assert capacity > 0;
+- @Override
+- public final List<String> cipherSuites() {
+- return unmodifiableCiphers;
+- }
-
-- // Number of produced bytes
-- int bytesProduced = 0;
-- int bytesConsumed = 0;
-- try {
-- for (; srcsOffset < srcsEndOffset; ++srcsOffset) {
-- ByteBuffer src = srcs[srcsOffset];
-- int remaining = src.remaining();
-- if (remaining == 0) {
-- // We must skip empty buffers as BIO_write will return 0 if asked to write something
-- // with length 0.
-- continue;
-- }
-- // Write more encrypted data into the BIO. Ensure we only read one packet at a time as
-- // stated in the SSLEngine javadocs.
-- int pendingEncryptedBytes = min(packetLength, remaining);
-- ByteBuf bioWriteCopyBuf = writeEncryptedData(src, pendingEncryptedBytes);
-- try {
-- readLoop:
-- for (; dstsOffset < dstsEndOffset; ++dstsOffset) {
-- ByteBuffer dst = dsts[dstsOffset];
-- if (!dst.hasRemaining()) {
-- // No space left in the destination buffer, skip it.
-- continue;
-- }
+- @Override
+- public final long sessionCacheSize() {
+- return sessionCacheSize;
+- }
-
-- int bytesRead = readPlaintextData(dst);
-- // We are directly using the ByteBuffer memory for the write, and so we only know what
-- // has been consumed after we let SSL decrypt the data. At this point we should update
-- // the number of bytes consumed, update the ByteBuffer position, and release temp
-- // ByteBuf.
-- int localBytesConsumed = pendingEncryptedBytes - SSL.bioLengthByteBuffer(networkBIO);
-- bytesConsumed += localBytesConsumed;
-- packetLength -= localBytesConsumed;
-- pendingEncryptedBytes -= localBytesConsumed;
-- src.position(src.position() + localBytesConsumed);
+- @Override
+- public final long sessionTimeout() {
+- return sessionTimeout;
+- }
-
-- if (bytesRead > 0) {
-- bytesProduced += bytesRead;
+- @Override
+- public ApplicationProtocolNegotiator applicationProtocolNegotiator() {
+- return apn;
+- }
-
-- if (!dst.hasRemaining()) {
-- // Move to the next dst buffer as this one is full.
-- continue;
-- }
-- if (packetLength == 0) {
-- // We read everything return now.
-- return newResultMayFinishHandshake(isInboundDone() ? CLOSED : OK, status,
-- bytesConsumed, bytesProduced);
-- }
-- // try to write again to the BIO. stop reading from it by break out of the readLoop.
-- break;
-- } else {
-- int sslError = SSL.getError(ssl, bytesRead);
-- if (sslError == SSL.SSL_ERROR_WANT_READ || sslError == SSL.SSL_ERROR_WANT_WRITE) {
-- // break to the outer loop as we want to read more data which means we need to
-- // write more to the BIO.
-- break readLoop;
-- } else if (sslError == SSL.SSL_ERROR_ZERO_RETURN) {
-- // This means the connection was shutdown correctly, close inbound and outbound
-- if (!receivedShutdown) {
-- closeAll();
-- }
-- return newResultMayFinishHandshake(isInboundDone() ? CLOSED : OK, status,
-- bytesConsumed, bytesProduced);
-- } else {
-- return sslReadErrorResult(SSL.getLastErrorNumber(), bytesConsumed,
-- bytesProduced);
-- }
-- }
-- }
+- @Override
+- public final boolean isClient() {
+- return mode == SSL.SSL_MODE_CLIENT;
+- }
-
-- // Either we have no more dst buffers to put the data, or no more data to generate; we are done.
-- if (dstsOffset >= dstsEndOffset || packetLength == 0) {
-- break;
-- }
-- } finally {
-- if (bioWriteCopyBuf != null) {
-- bioWriteCopyBuf.release();
-- }
-- }
-- }
-- } finally {
-- SSL.bioClearByteBuffer(networkBIO);
-- rejectRemoteInitiatedRenegotiation();
-- }
+- @Override
+- public final SSLEngine newEngine(ByteBufAllocator alloc, String peerHost, int peerPort) {
+- return newEngine0(alloc, peerHost, peerPort, true);
+- }
-
-- // Check to see if we received a close_notify message from the peer.
-- if (!receivedShutdown && (SSL.getShutdown(ssl) & SSL.SSL_RECEIVED_SHUTDOWN) == SSL.SSL_RECEIVED_SHUTDOWN) {
-- closeAll();
-- }
+- @Override
+- protected final SslHandler newHandler(ByteBufAllocator alloc, boolean startTls) {
+- return new SslHandler(newEngine0(alloc, null, -1, false), startTls);
+- }
-
-- return newResultMayFinishHandshake(isInboundDone() ? CLOSED : OK, status, bytesConsumed, bytesProduced);
-- }
+- @Override
+- protected final SslHandler newHandler(ByteBufAllocator alloc, String peerHost, int peerPort, boolean startTls) {
+- return new SslHandler(newEngine0(alloc, peerHost, peerPort, false), startTls);
- }
-
-- private SSLEngineResult sslReadErrorResult(int err, int bytesConsumed, int bytesProduced) throws SSLException {
-- String errStr = SSL.getErrorString(err);
+- @Override
+- protected SslHandler newHandler(ByteBufAllocator alloc, boolean startTls, Executor executor) {
+- return new SslHandler(newEngine0(alloc, null, -1, false), startTls, executor);
+- }
-
-- // Check if we have a pending handshakeException and if so see if we need to consume all pending data from the
-- // BIO first or can just shutdown and throw it now.
-- // This is needed so we ensure close_notify etc is correctly send to the remote peer.
-- // See https://github.com/netty/netty/issues/3900
-- if (SSL.bioLengthNonApplication(networkBIO) > 0) {
-- if (handshakeException == null && handshakeState != HandshakeState.FINISHED) {
-- // we seems to have data left that needs to be transfered and so the user needs
-- // call wrap(...). Store the error so we can pick it up later.
-- handshakeException = new SSLHandshakeException(errStr);
-- }
-- return new SSLEngineResult(OK, NEED_WRAP, bytesConsumed, bytesProduced);
-- }
-- throw shutdownWithError("SSL_read", errStr);
+- @Override
+- protected SslHandler newHandler(ByteBufAllocator alloc, String peerHost, int peerPort,
+- boolean startTls, Executor executor) {
+- return new SslHandler(newEngine0(alloc, peerHost, peerPort, false), executor);
- }
-
-- private void closeAll() throws SSLException {
-- receivedShutdown = true;
-- closeOutbound();
-- closeInbound();
+- SSLEngine newEngine0(ByteBufAllocator alloc, String peerHost, int peerPort, boolean jdkCompatibilityMode) {
+- return new ReferenceCountedOpenSslEngine(this, alloc, peerHost, peerPort, jdkCompatibilityMode, true);
- }
-
-- private void rejectRemoteInitiatedRenegotiation() throws SSLHandshakeException {
-- if (rejectRemoteInitiatedRenegotiation && SSL.getHandshakeCount(ssl) > 1) {
-- // TODO: In future versions me may also want to send a fatal_alert to the client and so notify it
-- // that the renegotiation failed.
-- shutdown();
-- throw new SSLHandshakeException("remote-initiated renegotiation not allowed");
-- }
+- /**
+- * Returns a new server-side {@link SSLEngine} with the current configuration.
+- */
+- @Override
+- public final SSLEngine newEngine(ByteBufAllocator alloc) {
+- return newEngine(alloc, null, -1);
- }
-
-- public final SSLEngineResult unwrap(final ByteBuffer[] srcs, final ByteBuffer[] dsts) throws SSLException {
-- return unwrap(srcs, 0, srcs.length, dsts, 0, dsts.length);
+- /**
+- * Returns the pointer to the {@code SSL_CTX} object for this {@link ReferenceCountedOpenSslContext}.
+- * Be aware that it is freed as soon as the {@link #finalize()} method is called.
+- * At this point {@code 0} will be returned.
+- *
+- * @deprecated this method is considered unsafe as the returned pointer may be released later. Dont use it!
+- */
+- @Deprecated
+- public final long context() {
+- return sslCtxPointer();
- }
-
-- private ByteBuffer[] singleSrcBuffer(ByteBuffer src) {
-- singleSrcBuffer[0] = src;
-- return singleSrcBuffer;
+- /**
+- * Returns the stats of this context.
+- *
+- * @deprecated use {@link #sessionContext#stats()}
+- */
+- @Deprecated
+- public final OpenSslSessionStats stats() {
+- return sessionContext().stats();
- }
-
-- private void resetSingleSrcBuffer() {
-- singleSrcBuffer[0] = null;
+- /**
+- * {@deprecated Renegotiation is not supported}
+- * Specify if remote initiated renegotiation is supported or not. If not supported and the remote side tries
+- * to initiate a renegotiation a {@link SSLHandshakeException} will be thrown during decoding.
+- */
+- @Deprecated
+- public void setRejectRemoteInitiatedRenegotiation(boolean rejectRemoteInitiatedRenegotiation) {
+- if (!rejectRemoteInitiatedRenegotiation) {
+- throw new UnsupportedOperationException("Renegotiation is not supported");
+- }
- }
-
-- private ByteBuffer[] singleDstBuffer(ByteBuffer src) {
-- singleDstBuffer[0] = src;
-- return singleDstBuffer;
+- /**
+- * {@deprecated Renegotiation is not supported}
+- * @return {@code true} because renegotiation is not supported.
+- */
+- @Deprecated
+- public boolean getRejectRemoteInitiatedRenegotiation() {
+- return true;
- }
-
-- private void resetSingleDstBuffer() {
-- singleDstBuffer[0] = null;
+- /**
+- * Set the size of the buffer used by the BIO for non-application based writes
+- * (e.g. handshake, renegotiation, etc...).
+- */
+- public void setBioNonApplicationBufferSize(int bioNonApplicationBufferSize) {
+- this.bioNonApplicationBufferSize =
+- checkPositiveOrZero(bioNonApplicationBufferSize, "bioNonApplicationBufferSize");
+- }
+-
+- /**
+- * Returns the size of the buffer used by the BIO for non-application based writes
+- */
+- public int getBioNonApplicationBufferSize() {
+- return bioNonApplicationBufferSize;
+- }
+-
+- /**
+- * Sets the SSL session ticket keys of this context.
+- *
+- * @deprecated use {@link OpenSslSessionContext#setTicketKeys(byte[])}
+- */
+- @Deprecated
+- public final void setTicketKeys(byte[] keys) {
+- sessionContext().setTicketKeys(keys);
- }
-
- @Override
-- public final synchronized SSLEngineResult unwrap(
-- final ByteBuffer src, final ByteBuffer[] dsts, final int offset, final int length) throws SSLException {
+- public abstract OpenSslSessionContext sessionContext();
+-
+- /**
+- * Returns the pointer to the {@code SSL_CTX} object for this {@link ReferenceCountedOpenSslContext}.
+- * Be aware that it is freed as soon as the {@link #release()} method is called.
+- * At this point {@code 0} will be returned.
+- *
+- * @deprecated this method is considered unsafe as the returned pointer may be released later. Dont use it!
+- */
+- @Deprecated
+- public final long sslCtxPointer() {
+- Lock readerLock = ctxLock.readLock();
+- readerLock.lock();
- try {
-- return unwrap(singleSrcBuffer(src), 0, 1, dsts, offset, length);
+- return SSLContext.getSslCtx(ctx);
- } finally {
-- resetSingleSrcBuffer();
+- readerLock.unlock();
- }
- }
-
-- @Override
-- public final synchronized SSLEngineResult wrap(ByteBuffer src, ByteBuffer dst) throws SSLException {
+- /**
+- * Set the {@link OpenSslPrivateKeyMethod} to use. This allows to offload private-key operations
+- * if needed.
+- *
+- * This method is currently only supported when {@code BoringSSL} is used.
+- *
+- * @param method method to use.
+- */
+- @UnstableApi
+- public final void setPrivateKeyMethod(OpenSslPrivateKeyMethod method) {
+- ObjectUtil.checkNotNull(method, "method");
+- Lock writerLock = ctxLock.writeLock();
+- writerLock.lock();
- try {
-- return wrap(singleSrcBuffer(src), dst);
+- SSLContext.setPrivateKeyMethod(ctx, new PrivateKeyMethod(engineMap, method));
- } finally {
-- resetSingleSrcBuffer();
+- writerLock.unlock();
- }
- }
-
-- @Override
-- public final synchronized SSLEngineResult unwrap(ByteBuffer src, ByteBuffer dst) throws SSLException {
+- public final void setUseTasks(boolean useTasks) {
+- Lock writerLock = ctxLock.writeLock();
+- writerLock.lock();
- try {
-- return unwrap(singleSrcBuffer(src), singleDstBuffer(dst));
+- SSLContext.setUseTasks(ctx, useTasks);
- } finally {
-- resetSingleSrcBuffer();
-- resetSingleDstBuffer();
+- writerLock.unlock();
- }
- }
-
-- @Override
-- public final synchronized SSLEngineResult unwrap(ByteBuffer src, ByteBuffer[] dsts) throws SSLException {
+- // IMPORTANT: This method must only be called from either the constructor or the finalizer as a user MUST never
+- // get access to an OpenSslSessionContext after this method was called to prevent the user from
+- // producing a segfault.
+- private void destroy() {
+- Lock writerLock = ctxLock.writeLock();
+- writerLock.lock();
- try {
-- return unwrap(singleSrcBuffer(src), dsts);
-- } finally {
-- resetSingleSrcBuffer();
-- }
-- }
--
-- @Override
-- public final Runnable getDelegatedTask() {
-- // Currently, we do not delegate SSL computation tasks
-- // TODO: in the future, possibly create tasks to do encrypt / decrypt async
--
-- return null;
-- }
--
-- @Override
-- public final synchronized void closeInbound() throws SSLException {
-- if (isInboundDone) {
-- return;
-- }
--
-- isInboundDone = true;
+- if (ctx != 0) {
+- if (enableOcsp) {
+- SSLContext.disableOcsp(ctx);
+- }
-
-- if (isOutboundDone()) {
-- // Only call shutdown if there is no outbound data pending.
-- // See https://github.com/netty/netty/issues/6167
-- shutdown();
-- }
+- SSLContext.free(ctx);
+- ctx = 0;
-
-- if (handshakeState != HandshakeState.NOT_STARTED && !receivedShutdown) {
-- throw new SSLException(
-- "Inbound closed before receiving peer's close_notify: possible truncation attack?");
+- OpenSslSessionContext context = sessionContext();
+- if (context != null) {
+- context.destroy();
+- }
+- }
+- } finally {
+- writerLock.unlock();
- }
- }
-
-- @Override
-- public final synchronized boolean isInboundDone() {
-- return isInboundDone;
+- protected static X509Certificate[] certificates(byte[][] chain) {
+- X509Certificate[] peerCerts = new X509Certificate[chain.length];
+- for (int i = 0; i < peerCerts.length; i++) {
+- peerCerts[i] = new OpenSslX509Certificate(chain[i]);
+- }
+- return peerCerts;
- }
-
-- @Override
-- public final synchronized void closeOutbound() {
-- if (outboundClosed) {
-- return;
+- protected static X509TrustManager chooseTrustManager(TrustManager[] managers) {
+- for (TrustManager m : managers) {
+- if (m instanceof X509TrustManager) {
+- if (PlatformDependent.javaVersion() >= 7) {
+- return OpenSslX509TrustManagerWrapper.wrapIfNeeded((X509TrustManager) m);
+- }
+- return (X509TrustManager) m;
+- }
- }
+- throw new IllegalStateException("no X509TrustManager found");
+- }
-
-- outboundClosed = true;
--
-- if (handshakeState != HandshakeState.NOT_STARTED && !isDestroyed()) {
-- int mode = SSL.getShutdown(ssl);
-- if ((mode & SSL.SSL_SENT_SHUTDOWN) != SSL.SSL_SENT_SHUTDOWN) {
-- doSSLShutdown();
+- protected static X509KeyManager chooseX509KeyManager(KeyManager[] kms) {
+- for (KeyManager km : kms) {
+- if (km instanceof X509KeyManager) {
+- return (X509KeyManager) km;
- }
-- } else {
-- // engine closing before initial handshake
-- shutdown();
- }
+- throw new IllegalStateException("no X509KeyManager found");
- }
-
- /**
-- * Attempt to call {@link SSL#shutdownSSL(long)}.
-- * @return {@code false} if the call to {@link SSL#shutdownSSL(long)} was not attempted or returned an error.
+- * Translate a {@link ApplicationProtocolConfig} object to a
+- * {@link OpenSslApplicationProtocolNegotiator} object.
+- *
+- * @param config The configuration which defines the translation
+- * @return The results of the translation
- */
-- private boolean doSSLShutdown() {
-- if (SSL.isInInit(ssl) != 0) {
-- // Only try to call SSL_shutdown if we are not in the init state anymore.
-- // Otherwise we will see 'error:140E0197:SSL routines:SSL_shutdown:shutdown while in init' in our logs.
-- //
-- // See also http://hg.nginx.org/nginx/rev/062c189fee20
-- return false;
+- @SuppressWarnings("deprecation")
+- static OpenSslApplicationProtocolNegotiator toNegotiator(ApplicationProtocolConfig config) {
+- if (config == null) {
+- return NONE_PROTOCOL_NEGOTIATOR;
- }
-- int err = SSL.shutdownSSL(ssl);
-- if (err < 0) {
-- int sslErr = SSL.getError(ssl, err);
-- if (sslErr == SSL.SSL_ERROR_SYSCALL || sslErr == SSL.SSL_ERROR_SSL) {
-- if (logger.isDebugEnabled()) {
-- logger.debug("SSL_shutdown failed: OpenSSL error: {}", SSL.getLastError());
+-
+- switch (config.protocol()) {
+- case NONE:
+- return NONE_PROTOCOL_NEGOTIATOR;
+- case ALPN:
+- case NPN:
+- case NPN_AND_ALPN:
+- switch (config.selectedListenerFailureBehavior()) {
+- case CHOOSE_MY_LAST_PROTOCOL:
+- case ACCEPT:
+- switch (config.selectorFailureBehavior()) {
+- case CHOOSE_MY_LAST_PROTOCOL:
+- case NO_ADVERTISE:
+- return new OpenSslDefaultApplicationProtocolNegotiator(
+- config);
+- default:
+- throw new UnsupportedOperationException(
+- new StringBuilder("OpenSSL provider does not support ")
+- .append(config.selectorFailureBehavior())
+- .append(" behavior").toString());
+- }
+- default:
+- throw new UnsupportedOperationException(
+- new StringBuilder("OpenSSL provider does not support ")
+- .append(config.selectedListenerFailureBehavior())
+- .append(" behavior").toString());
- }
-- // There was an internal error -- shutdown
-- shutdown();
-- return false;
-- }
-- SSL.clearError();
+- default:
+- throw new Error();
- }
-- return true;
- }
-
-- @Override
-- public final synchronized boolean isOutboundDone() {
-- // Check if there is anything left in the outbound buffer.
-- // We need to ensure we only call SSL.pendingWrittenBytesInBIO(...) if the engine was not destroyed yet.
-- return outboundClosed && (networkBIO == 0 || SSL.bioLengthNonApplication(networkBIO) == 0);
+- @SuppressJava6Requirement(reason = "Guarded by java version check")
+- static boolean useExtendedTrustManager(X509TrustManager trustManager) {
+- return PlatformDependent.javaVersion() >= 7 && trustManager instanceof X509ExtendedTrustManager;
- }
-
- @Override
-- public final String[] getSupportedCipherSuites() {
-- return OpenSsl.AVAILABLE_CIPHER_SUITES.toArray(new String[OpenSsl.AVAILABLE_CIPHER_SUITES.size()]);
+- public final int refCnt() {
+- return refCnt.refCnt();
- }
-
- @Override
-- public final String[] getEnabledCipherSuites() {
-- final String[] enabled;
-- synchronized (this) {
-- if (!isDestroyed()) {
-- enabled = SSL.getCiphers(ssl);
-- } else {
-- return EmptyArrays.EMPTY_STRINGS;
-- }
-- }
-- if (enabled == null) {
-- return EmptyArrays.EMPTY_STRINGS;
-- } else {
-- synchronized (this) {
-- for (int i = 0; i < enabled.length; i++) {
-- String mapped = toJavaCipherSuite(enabled[i]);
-- if (mapped != null) {
-- enabled[i] = mapped;
-- }
-- }
-- }
-- return enabled;
-- }
+- public final ReferenceCounted retain() {
+- refCnt.retain();
+- return this;
- }
-
- @Override
-- public final void setEnabledCipherSuites(String[] cipherSuites) {
-- checkNotNull(cipherSuites, "cipherSuites");
--
-- final StringBuilder buf = new StringBuilder();
-- for (String c: cipherSuites) {
-- if (c == null) {
-- break;
-- }
--
-- String converted = CipherSuiteConverter.toOpenSsl(c);
-- if (converted == null) {
-- converted = c;
-- }
--
-- if (!OpenSsl.isCipherSuiteAvailable(converted)) {
-- throw new IllegalArgumentException("unsupported cipher suite: " + c + '(' + converted + ')');
-- }
--
-- buf.append(converted);
-- buf.append(':');
-- }
--
-- if (buf.length() == 0) {
-- throw new IllegalArgumentException("empty cipher suites");
-- }
-- buf.setLength(buf.length() - 1);
--
-- final String cipherSuiteSpec = buf.toString();
--
-- synchronized (this) {
-- if (!isDestroyed()) {
-- try {
-- SSL.setCipherSuites(ssl, cipherSuiteSpec);
-- } catch (Exception e) {
-- throw new IllegalStateException("failed to enable cipher suites: " + cipherSuiteSpec, e);
-- }
-- } else {
-- throw new IllegalStateException("failed to enable cipher suites: " + cipherSuiteSpec);
-- }
-- }
+- public final ReferenceCounted retain(int increment) {
+- refCnt.retain(increment);
+- return this;
- }
-
- @Override
-- public final String[] getSupportedProtocols() {
-- return OpenSsl.SUPPORTED_PROTOCOLS_SET.toArray(new String[OpenSsl.SUPPORTED_PROTOCOLS_SET.size()]);
+- public final ReferenceCounted touch() {
+- refCnt.touch();
+- return this;
- }
-
- @Override
-- public final String[] getEnabledProtocols() {
-- List<String> enabled = new ArrayList<String>(6);
-- // Seems like there is no way to explicit disable SSLv2Hello in openssl so it is always enabled
-- enabled.add(OpenSsl.PROTOCOL_SSL_V2_HELLO);
--
-- int opts;
-- synchronized (this) {
-- if (!isDestroyed()) {
-- opts = SSL.getOptions(ssl);
-- } else {
-- return enabled.toArray(new String[1]);
-- }
-- }
-- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_TLSv1, OpenSsl.PROTOCOL_TLS_V1)) {
-- enabled.add(OpenSsl.PROTOCOL_TLS_V1);
-- }
-- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_TLSv1_1, OpenSsl.PROTOCOL_TLS_V1_1)) {
-- enabled.add(OpenSsl.PROTOCOL_TLS_V1_1);
-- }
-- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_TLSv1_2, OpenSsl.PROTOCOL_TLS_V1_2)) {
-- enabled.add(OpenSsl.PROTOCOL_TLS_V1_2);
-- }
-- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_SSLv2, OpenSsl.PROTOCOL_SSL_V2)) {
-- enabled.add(OpenSsl.PROTOCOL_SSL_V2);
-- }
-- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_SSLv3, OpenSsl.PROTOCOL_SSL_V3)) {
-- enabled.add(OpenSsl.PROTOCOL_SSL_V3);
-- }
-- return enabled.toArray(new String[enabled.size()]);
+- public final ReferenceCounted touch(Object hint) {
+- refCnt.touch(hint);
+- return this;
- }
-
-- private static boolean isProtocolEnabled(int opts, int disableMask, String protocolString) {
-- // We also need to check if the actual protocolString is supported as depending on the openssl API
-- // implementations it may use a disableMask of 0 (BoringSSL is doing this for example).
-- return (opts & disableMask) == 0 && OpenSsl.SUPPORTED_PROTOCOLS_SET.contains(protocolString);
+- @Override
+- public final boolean release() {
+- return refCnt.release();
- }
-
- @Override
-- public final void setEnabledProtocols(String[] protocols) {
-- if (protocols == null) {
-- // This is correct from the API docs
-- throw new IllegalArgumentException();
+- public final boolean release(int decrement) {
+- return refCnt.release(decrement);
+- }
+-
+- abstract static class AbstractCertificateVerifier extends CertificateVerifier {
+- private final OpenSslEngineMap engineMap;
+-
+- AbstractCertificateVerifier(OpenSslEngineMap engineMap) {
+- this.engineMap = engineMap;
- }
-- boolean sslv2 = false;
-- boolean sslv3 = false;
-- boolean tlsv1 = false;
-- boolean tlsv1_1 = false;
-- boolean tlsv1_2 = false;
-- for (String p: protocols) {
-- if (!OpenSsl.SUPPORTED_PROTOCOLS_SET.contains(p)) {
-- throw new IllegalArgumentException("Protocol " + p + " is not supported.");
-- }
-- if (p.equals(OpenSsl.PROTOCOL_SSL_V2)) {
-- sslv2 = true;
-- } else if (p.equals(OpenSsl.PROTOCOL_SSL_V3)) {
-- sslv3 = true;
-- } else if (p.equals(OpenSsl.PROTOCOL_TLS_V1)) {
-- tlsv1 = true;
-- } else if (p.equals(OpenSsl.PROTOCOL_TLS_V1_1)) {
-- tlsv1_1 = true;
-- } else if (p.equals(OpenSsl.PROTOCOL_TLS_V1_2)) {
-- tlsv1_2 = true;
+-
+- @Override
+- public final int verify(long ssl, byte[][] chain, String auth) {
+- final ReferenceCountedOpenSslEngine engine = engineMap.get(ssl);
+- if (engine == null) {
+- // May be null if it was destroyed in the meantime.
+- return CertificateVerifier.X509_V_ERR_UNSPECIFIED;
- }
-- }
-- synchronized (this) {
-- if (!isDestroyed()) {
-- // Clear out options which disable protocols
-- SSL.clearOptions(ssl, SSL.SSL_OP_NO_SSLv2 | SSL.SSL_OP_NO_SSLv3 | SSL.SSL_OP_NO_TLSv1 |
-- SSL.SSL_OP_NO_TLSv1_1 | SSL.SSL_OP_NO_TLSv1_2);
+- X509Certificate[] peerCerts = certificates(chain);
+- try {
+- verify(engine, peerCerts, auth);
+- return CertificateVerifier.X509_V_OK;
+- } catch (Throwable cause) {
+- logger.debug("verification of certificate failed", cause);
+- engine.initHandshakeException(cause);
-
-- int opts = 0;
-- if (!sslv2) {
-- opts |= SSL.SSL_OP_NO_SSLv2;
-- }
-- if (!sslv3) {
-- opts |= SSL.SSL_OP_NO_SSLv3;
+- // Try to extract the correct error code that should be used.
+- if (cause instanceof OpenSslCertificateException) {
+- // This will never return a negative error code as its validated when constructing the
+- // OpenSslCertificateException.
+- return ((OpenSslCertificateException) cause).errorCode();
- }
-- if (!tlsv1) {
-- opts |= SSL.SSL_OP_NO_TLSv1;
+- if (cause instanceof CertificateExpiredException) {
+- return CertificateVerifier.X509_V_ERR_CERT_HAS_EXPIRED;
- }
-- if (!tlsv1_1) {
-- opts |= SSL.SSL_OP_NO_TLSv1_1;
+- if (cause instanceof CertificateNotYetValidException) {
+- return CertificateVerifier.X509_V_ERR_CERT_NOT_YET_VALID;
- }
-- if (!tlsv1_2) {
-- opts |= SSL.SSL_OP_NO_TLSv1_2;
+- if (PlatformDependent.javaVersion() >= 7) {
+- return translateToError(cause);
- }
-
-- // Disable protocols we do not want
-- SSL.setOptions(ssl, opts);
-- } else {
-- throw new IllegalStateException("failed to enable protocols: " + Arrays.asList(protocols));
+- // Could not detect a specific error code to use, so fallback to a default code.
+- return CertificateVerifier.X509_V_ERR_UNSPECIFIED;
- }
- }
-- }
--
-- @Override
-- public final SSLSession getSession() {
-- return session;
-- }
--
-- @Override
-- public final synchronized void beginHandshake() throws SSLException {
-- switch (handshakeState) {
-- case STARTED_IMPLICITLY:
-- checkEngineClosed(BEGIN_HANDSHAKE_ENGINE_CLOSED);
-
-- // A user did not start handshake by calling this method by him/herself,
-- // but handshake has been started already by wrap() or unwrap() implicitly.
-- // Because it's the user's first time to call this method, it is unfair to
-- // raise an exception. From the user's standpoint, he or she never asked
-- // for renegotiation.
+- @SuppressJava6Requirement(reason = "Usage guarded by java version check")
+- private static int translateToError(Throwable cause) {
+- if (cause instanceof CertificateRevokedException) {
+- return CertificateVerifier.X509_V_ERR_CERT_REVOKED;
+- }
-
-- handshakeState = HandshakeState.STARTED_EXPLICITLY; // Next time this method is invoked by the user,
-- // we should raise an exception.
-- break;
-- case STARTED_EXPLICITLY:
-- // Nothing to do as the handshake is not done yet.
-- break;
-- case FINISHED:
-- if (clientMode) {
-- // Only supported for server mode at the moment.
-- throw RENEGOTIATION_UNSUPPORTED;
-- }
-- // For renegotiate on the server side we need to issue the following command sequence with openssl:
-- //
-- // SSL_renegotiate(ssl)
-- // SSL_do_handshake(ssl)
-- // ssl->state = SSL_ST_ACCEPT
-- // SSL_do_handshake(ssl)
-- //
-- // Because of this we fall-through to call handshake() after setting the state, as this will also take
-- // care of updating the internal OpenSslSession object.
-- //
-- // See also:
-- // https://github.com/apache/httpd/blob/2.4.16/modules/ssl/ssl_engine_kernel...
-- // http://h71000.www7.hp.com/doc/83final/ba554_90007/ch04s03.html
-- int status;
-- if ((status = SSL.renegotiate(ssl)) != 1 || (status = SSL.doHandshake(ssl)) != 1) {
-- int err = SSL.getError(ssl, status);
-- if (err == SSL.SSL_ERROR_WANT_READ || err == SSL.SSL_ERROR_WANT_WRITE) {
-- // If the internal SSL buffer is small it is possible that doHandshake may "fail" because
-- // there is not enough room to write, so we should wait until the renegotiation has been.
-- renegotiationPending = true;
-- handshakeState = HandshakeState.STARTED_EXPLICITLY;
-- lastAccessed = System.currentTimeMillis();
-- return;
-- } else {
-- throw shutdownWithError("renegotiation failed");
+- // The X509TrustManagerImpl uses a Validator which wraps a CertPathValidatorException into
+- // an CertificateException. So we need to handle the wrapped CertPathValidatorException to be
+- // able to send the correct alert.
+- Throwable wrapped = cause.getCause();
+- while (wrapped != null) {
+- if (wrapped instanceof CertPathValidatorException) {
+- CertPathValidatorException ex = (CertPathValidatorException) wrapped;
+- CertPathValidatorException.Reason reason = ex.getReason();
+- if (reason == CertPathValidatorException.BasicReason.EXPIRED) {
+- return CertificateVerifier.X509_V_ERR_CERT_HAS_EXPIRED;
+- }
+- if (reason == CertPathValidatorException.BasicReason.NOT_YET_VALID) {
+- return CertificateVerifier.X509_V_ERR_CERT_NOT_YET_VALID;
+- }
+- if (reason == CertPathValidatorException.BasicReason.REVOKED) {
+- return CertificateVerifier.X509_V_ERR_CERT_REVOKED;
- }
- }
+- wrapped = wrapped.getCause();
+- }
+- return CertificateVerifier.X509_V_ERR_UNSPECIFIED;
+- }
-
-- SSL.setState(ssl, SSL.SSL_ST_ACCEPT);
+- abstract void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts,
+- String auth) throws Exception;
+- }
-
-- lastAccessed = System.currentTimeMillis();
+- private static final class DefaultOpenSslEngineMap implements OpenSslEngineMap {
+- private final Map<Long, ReferenceCountedOpenSslEngine> engines = PlatformDependent.newConcurrentHashMap();
-
-- // fall-through
-- case NOT_STARTED:
-- handshakeState = HandshakeState.STARTED_EXPLICITLY;
-- handshake();
-- break;
-- default:
-- throw new Error();
+- @Override
+- public ReferenceCountedOpenSslEngine remove(long ssl) {
+- return engines.remove(ssl);
- }
-- }
-
-- private void checkEngineClosed(SSLException cause) throws SSLException {
-- if (isDestroyed()) {
-- throw cause;
+- @Override
+- public void add(ReferenceCountedOpenSslEngine engine) {
+- engines.put(engine.sslPointer(), engine);
- }
-- }
-
-- private static SSLEngineResult.HandshakeStatus pendingStatus(int pendingStatus) {
-- // Depending on if there is something left in the BIO we need to WRAP or UNWRAP
-- return pendingStatus > 0 ? NEED_WRAP : NEED_UNWRAP;
+- @Override
+- public ReferenceCountedOpenSslEngine get(long ssl) {
+- return engines.get(ssl);
+- }
- }
-
-- private static boolean isEmpty(Object[] arr) {
-- return arr == null || arr.length == 0;
-- }
+- static void setKeyMaterial(long ctx, X509Certificate[] keyCertChain, PrivateKey key, String keyPassword)
+- throws SSLException {
+- /* Load the certificate file and private key. */
+- long keyBio = 0;
+- long keyCertChainBio = 0;
+- long keyCertChainBio2 = 0;
+- PemEncoded encoded = null;
+- try {
+- // Only encode one time
+- encoded = PemX509Certificate.toPEM(ByteBufAllocator.DEFAULT, true, keyCertChain);
+- keyCertChainBio = toBIO(ByteBufAllocator.DEFAULT, encoded.retain());
+- keyCertChainBio2 = toBIO(ByteBufAllocator.DEFAULT, encoded.retain());
-
-- private static boolean isEmpty(byte[] cert) {
-- return cert == null || cert.length == 0;
-- }
+- if (key != null) {
+- keyBio = toBIO(ByteBufAllocator.DEFAULT, key);
+- }
-
-- private SSLEngineResult.HandshakeStatus handshake() throws SSLException {
-- if (handshakeState == HandshakeState.FINISHED) {
-- return FINISHED;
+- SSLContext.setCertificateBio(
+- ctx, keyCertChainBio, keyBio,
+- keyPassword == null ? StringUtil.EMPTY_STRING : keyPassword);
+- // We may have more then one cert in the chain so add all of them now.
+- SSLContext.setCertificateChainBio(ctx, keyCertChainBio2, true);
+- } catch (SSLException e) {
+- throw e;
+- } catch (Exception e) {
+- throw new SSLException("failed to set certificate and key", e);
+- } finally {
+- freeBio(keyBio);
+- freeBio(keyCertChainBio);
+- freeBio(keyCertChainBio2);
+- if (encoded != null) {
+- encoded.release();
+- }
- }
-- checkEngineClosed(HANDSHAKE_ENGINE_CLOSED);
+- }
-
-- // Check if we have a pending handshakeException and if so see if we need to consume all pending data from the
-- // BIO first or can just shutdown and throw it now.
-- // This is needed so we ensure close_notify etc is correctly send to the remote peer.
-- // See https://github.com/netty/netty/issues/3900
-- SSLHandshakeException exception = handshakeException;
-- if (exception != null) {
-- if (SSL.bioLengthNonApplication(networkBIO) > 0) {
-- // There is something pending, we need to consume it first via a WRAP so we don't loose anything.
-- return NEED_WRAP;
-- }
-- // No more data left to send to the remote peer, so null out the exception field, shutdown and throw
-- // the exception.
-- handshakeException = null;
-- shutdown();
-- throw exception;
+- static void freeBio(long bio) {
+- if (bio != 0) {
+- SSL.freeBIO(bio);
- }
+- }
-
-- // Adding the OpenSslEngine to the OpenSslEngineMap so it can be used in the AbstractCertificateVerifier.
-- engineMap.add(this);
-- if (lastAccessed == -1) {
-- lastAccessed = System.currentTimeMillis();
+- /**
+- * Return the pointer to a <a href="https://www.openssl.org/docs/crypto/BIO_get_mem_ptr.html">in-memory BIO</a>
+- * or {@code 0} if the {@code key} is {@code null}. The BIO contains the content of the {@code key}.
+- */
+- static long toBIO(ByteBufAllocator allocator, PrivateKey key) throws Exception {
+- if (key == null) {
+- return 0;
- }
-
-- if (!certificateSet && keyMaterialManager != null) {
-- certificateSet = true;
-- keyMaterialManager.setKeyMaterial(this);
+- PemEncoded pem = PemPrivateKey.toPEM(allocator, true, key);
+- try {
+- return toBIO(allocator, pem.retain());
+- } finally {
+- pem.release();
- }
+- }
-
-- int code = SSL.doHandshake(ssl);
-- if (code <= 0) {
-- // Check if we have a pending exception that was created during the handshake and if so throw it after
-- // shutdown the connection.
-- if (handshakeException != null) {
-- exception = handshakeException;
-- handshakeException = null;
-- shutdown();
-- throw exception;
-- }
+- /**
+- * Return the pointer to a <a href="https://www.openssl.org/docs/crypto/BIO_get_mem_ptr.html">in-memory BIO</a>
+- * or {@code 0} if the {@code certChain} is {@code null}. The BIO contains the content of the {@code certChain}.
+- */
+- static long toBIO(ByteBufAllocator allocator, X509Certificate... certChain) throws Exception {
+- if (certChain == null) {
+- return 0;
+- }
-
-- int sslError = SSL.getError(ssl, code);
-- if (sslError == SSL.SSL_ERROR_WANT_READ || sslError == SSL.SSL_ERROR_WANT_WRITE) {
-- return pendingStatus(SSL.bioLengthNonApplication(networkBIO));
-- } else {
-- // Everything else is considered as error
-- throw shutdownWithError("SSL_do_handshake");
-- }
+- if (certChain.length == 0) {
+- throw new IllegalArgumentException("certChain can't be empty");
- }
-- // if SSL_do_handshake returns > 0 or sslError == SSL.SSL_ERROR_NAME it means the handshake was finished.
-- session.handshakeFinished();
-- engineMap.remove(ssl);
-- return FINISHED;
-- }
-
-- private SSLEngineResult.HandshakeStatus mayFinishHandshake(SSLEngineResult.HandshakeStatus status)
-- throws SSLException {
-- if (status == NOT_HANDSHAKING && handshakeState != HandshakeState.FINISHED) {
-- // If the status was NOT_HANDSHAKING and we not finished the handshake we need to call
-- // SSL_do_handshake() again
-- return handshake();
+- PemEncoded pem = PemX509Certificate.toPEM(allocator, true, certChain);
+- try {
+- return toBIO(allocator, pem.retain());
+- } finally {
+- pem.release();
- }
-- return status;
- }
-
-- @Override
-- public final synchronized SSLEngineResult.HandshakeStatus getHandshakeStatus() {
-- // Check if we are in the initial handshake phase or shutdown phase
-- return needPendingStatus() ? pendingStatus(SSL.bioLengthNonApplication(networkBIO)) : NOT_HANDSHAKING;
-- }
+- static long toBIO(ByteBufAllocator allocator, PemEncoded pem) throws Exception {
+- try {
+- // We can turn direct buffers straight into BIOs. No need to
+- // make a yet another copy.
+- ByteBuf content = pem.content();
-
-- private SSLEngineResult.HandshakeStatus getHandshakeStatus(int pending) {
-- // Check if we are in the initial handshake phase or shutdown phase
-- return needPendingStatus() ? pendingStatus(pending) : NOT_HANDSHAKING;
+- if (content.isDirect()) {
+- return newBIO(content.retainedSlice());
+- }
+-
+- ByteBuf buffer = allocator.directBuffer(content.readableBytes());
+- try {
+- buffer.writeBytes(content, content.readerIndex(), content.readableBytes());
+- return newBIO(buffer.retainedSlice());
+- } finally {
+- try {
+- // If the contents of the ByteBuf is sensitive (e.g. a PrivateKey) we
+- // need to zero out the bytes of the copy before we're releasing it.
+- if (pem.isSensitive()) {
+- SslUtils.zeroout(buffer);
+- }
+- } finally {
+- buffer.release();
+- }
+- }
+- } finally {
+- pem.release();
+- }
- }
-
-- private boolean needPendingStatus() {
-- return handshakeState != HandshakeState.NOT_STARTED && !isDestroyed()
-- && (handshakeState != HandshakeState.FINISHED || isInboundDone() || isOutboundDone());
+- private static long newBIO(ByteBuf buffer) throws Exception {
+- try {
+- long bio = SSL.newMemBIO();
+- int readable = buffer.readableBytes();
+- if (SSL.bioWrite(bio, OpenSsl.memoryAddress(buffer) + buffer.readerIndex(), readable) != readable) {
+- SSL.freeBIO(bio);
+- throw new IllegalStateException("Could not write data to memory BIO");
+- }
+- return bio;
+- } finally {
+- buffer.release();
+- }
- }
-
- /**
-- * Converts the specified OpenSSL cipher suite to the Java cipher suite.
+- * Returns the {@link OpenSslKeyMaterialProvider} that should be used for OpenSSL. Depending on the given
+- * {@link KeyManagerFactory} this may cache the {@link OpenSslKeyMaterial} for better performance if it can
+- * ensure that the same material is always returned for the same alias.
- */
-- private String toJavaCipherSuite(String openSslCipherSuite) {
-- if (openSslCipherSuite == null) {
-- return null;
+- static OpenSslKeyMaterialProvider providerFor(KeyManagerFactory factory, String password) {
+- if (factory instanceof OpenSslX509KeyManagerFactory) {
+- return ((OpenSslX509KeyManagerFactory) factory).newProvider();
- }
-
-- String prefix = toJavaCipherSuitePrefix(SSL.getVersion(ssl));
-- return CipherSuiteConverter.toJava(openSslCipherSuite, prefix);
+- if (factory instanceof OpenSslCachingX509KeyManagerFactory) {
+- // The user explicit used OpenSslCachingX509KeyManagerFactory which signals us that its fine to cache.
+- return ((OpenSslCachingX509KeyManagerFactory) factory).newProvider(password);
+- }
+- // We can not be sure if the material may change at runtime so we will not cache it.
+- return new OpenSslKeyMaterialProvider(chooseX509KeyManager(factory.getKeyManagers()), password);
- }
-
-- /**
-- * Converts the protocol version string returned by {@link SSL#getVersion(long)} to protocol family string.
-- */
-- private static String toJavaCipherSuitePrefix(String protocolVersion) {
-- final char c;
-- if (protocolVersion == null || protocolVersion.isEmpty()) {
-- c = 0;
-- } else {
-- c = protocolVersion.charAt(0);
+- private static final class PrivateKeyMethod implements SSLPrivateKeyMethod {
+-
+- private final OpenSslEngineMap engineMap;
+- private final OpenSslPrivateKeyMethod keyMethod;
+- PrivateKeyMethod(OpenSslEngineMap engineMap, OpenSslPrivateKeyMethod keyMethod) {
+- this.engineMap = engineMap;
+- this.keyMethod = keyMethod;
- }
-
-- switch (c) {
-- case 'T':
-- return "TLS";
-- case 'S':
-- return "SSL";
-- default:
-- return "UNKNOWN";
+- private ReferenceCountedOpenSslEngine retrieveEngine(long ssl) throws SSLException {
+- ReferenceCountedOpenSslEngine engine = engineMap.get(ssl);
+- if (engine == null) {
+- throw new SSLException("Could not find a " +
+- StringUtil.simpleClassName(ReferenceCountedOpenSslEngine.class) + " for sslPointer " + ssl);
+- }
+- return engine;
- }
-- }
-
-- @Override
-- public final void setUseClientMode(boolean clientMode) {
-- if (clientMode != this.clientMode) {
-- throw new UnsupportedOperationException();
+- @Override
+- public byte[] sign(long ssl, int signatureAlgorithm, byte[] digest) throws Exception {
+- ReferenceCountedOpenSslEngine engine = retrieveEngine(ssl);
+- try {
+- return verifyResult(keyMethod.sign(engine, signatureAlgorithm, digest));
+- } catch (Exception e) {
+- engine.initHandshakeException(e);
+- throw e;
+- }
- }
-- }
-
-- @Override
-- public final boolean getUseClientMode() {
-- return clientMode;
-- }
+- @Override
+- public byte[] decrypt(long ssl, byte[] input) throws Exception {
+- ReferenceCountedOpenSslEngine engine = retrieveEngine(ssl);
+- try {
+- return verifyResult(keyMethod.decrypt(engine, input));
+- } catch (Exception e) {
+- engine.initHandshakeException(e);
+- throw e;
+- }
+- }
-
-- @Override
-- public final void setNeedClientAuth(boolean b) {
-- setClientAuth(b ? ClientAuth.REQUIRE : ClientAuth.NONE);
+- private static byte[] verifyResult(byte[] result) throws SignatureException {
+- if (result == null) {
+- throw new SignatureException();
+- }
+- return result;
+- }
- }
+-}
+diff --git a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngine.java b/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngine.java
+deleted file mode 100644
+index b404a1076b..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngine.java
++++ /dev/null
+@@ -1,2467 +0,0 @@
+-/*
+- * Copyright 2016 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- * http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-package io.netty.handler.ssl;
-
-- @Override
-- public final boolean getNeedClientAuth() {
-- return clientAuth == ClientAuth.REQUIRE;
-- }
+-import io.netty.buffer.ByteBuf;
+-import io.netty.buffer.ByteBufAllocator;
+-import io.netty.internal.tcnative.Buffer;
+-import io.netty.internal.tcnative.SSL;
+-import io.netty.util.AbstractReferenceCounted;
+-import io.netty.util.CharsetUtil;
+-import io.netty.util.ReferenceCounted;
+-import io.netty.util.ResourceLeakDetector;
+-import io.netty.util.ResourceLeakDetectorFactory;
+-import io.netty.util.ResourceLeakTracker;
+-import io.netty.util.internal.EmptyArrays;
+-import io.netty.util.internal.ObjectUtil;
+-import io.netty.util.internal.PlatformDependent;
+-import io.netty.util.internal.StringUtil;
+-import io.netty.util.internal.SuppressJava6Requirement;
+-import io.netty.util.internal.ThrowableUtil;
+-import io.netty.util.internal.UnstableApi;
+-import io.netty.util.internal.logging.InternalLogger;
+-import io.netty.util.internal.logging.InternalLoggerFactory;
-
-- @Override
-- public final void setWantClientAuth(boolean b) {
-- setClientAuth(b ? ClientAuth.OPTIONAL : ClientAuth.NONE);
-- }
+-import java.nio.ByteBuffer;
+-import java.nio.ReadOnlyBufferException;
+-import java.security.Principal;
+-import java.security.cert.Certificate;
+-import java.util.ArrayList;
+-import java.util.Arrays;
+-import java.util.Collection;
+-import java.util.Collections;
+-import java.util.HashMap;
+-import java.util.LinkedHashSet;
+-import java.util.List;
+-import java.util.Map;
+-import java.util.Set;
+-import java.util.concurrent.locks.Lock;
-
-- @Override
-- public final boolean getWantClientAuth() {
-- return clientAuth == ClientAuth.OPTIONAL;
-- }
+-import javax.crypto.spec.SecretKeySpec;
+-import javax.net.ssl.SSLEngine;
+-import javax.net.ssl.SSLEngineResult;
+-import javax.net.ssl.SSLException;
+-import javax.net.ssl.SSLHandshakeException;
+-import javax.net.ssl.SSLParameters;
+-import javax.net.ssl.SSLPeerUnverifiedException;
+-import javax.net.ssl.SSLSession;
+-import javax.net.ssl.SSLSessionBindingEvent;
+-import javax.net.ssl.SSLSessionBindingListener;
+-import javax.net.ssl.SSLSessionContext;
+-import javax.security.cert.X509Certificate;
-
-- /**
-- * See <a href="https://www.openssl.org/docs/man1.0.2/ssl/SSL_set_verify.html">SSL_set_verify</a> and
-- * {@link SSL#setVerify(long, int, int)}.
-- */
-- @UnstableApi
-- public final synchronized void setVerify(int verifyMode, int depth) {
-- SSL.setVerify(ssl, verifyMode, depth);
-- }
+-import static io.netty.handler.ssl.OpenSsl.memoryAddress;
+-import static io.netty.handler.ssl.SslUtils.PROTOCOL_SSL_V2;
+-import static io.netty.handler.ssl.SslUtils.PROTOCOL_SSL_V2_HELLO;
+-import static io.netty.handler.ssl.SslUtils.PROTOCOL_SSL_V3;
+-import static io.netty.handler.ssl.SslUtils.PROTOCOL_TLS_V1;
+-import static io.netty.handler.ssl.SslUtils.PROTOCOL_TLS_V1_1;
+-import static io.netty.handler.ssl.SslUtils.PROTOCOL_TLS_V1_2;
+-import static io.netty.handler.ssl.SslUtils.PROTOCOL_TLS_V1_3;
+-import static io.netty.handler.ssl.SslUtils.SSL_RECORD_HEADER_LENGTH;
+-import static io.netty.util.internal.ObjectUtil.checkNotNull;
+-import static java.lang.Integer.MAX_VALUE;
+-import static java.lang.Math.min;
+-import static javax.net.ssl.SSLEngineResult.HandshakeStatus.FINISHED;
+-import static javax.net.ssl.SSLEngineResult.HandshakeStatus.NEED_TASK;
+-import static javax.net.ssl.SSLEngineResult.HandshakeStatus.NEED_UNWRAP;
+-import static javax.net.ssl.SSLEngineResult.HandshakeStatus.NEED_WRAP;
+-import static javax.net.ssl.SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING;
+-import static javax.net.ssl.SSLEngineResult.Status.BUFFER_OVERFLOW;
+-import static javax.net.ssl.SSLEngineResult.Status.BUFFER_UNDERFLOW;
+-import static javax.net.ssl.SSLEngineResult.Status.CLOSED;
+-import static javax.net.ssl.SSLEngineResult.Status.OK;
-
-- private void setClientAuth(ClientAuth mode) {
-- if (clientMode) {
-- return;
-- }
-- synchronized (this) {
-- if (clientAuth == mode) {
-- // No need to issue any JNI calls if the mode is the same
-- return;
-- }
-- switch (mode) {
-- case NONE:
-- SSL.setVerify(ssl, SSL.SSL_CVERIFY_NONE, ReferenceCountedOpenSslContext.VERIFY_DEPTH);
-- break;
-- case REQUIRE:
-- SSL.setVerify(ssl, SSL.SSL_CVERIFY_REQUIRED, ReferenceCountedOpenSslContext.VERIFY_DEPTH);
-- break;
-- case OPTIONAL:
-- SSL.setVerify(ssl, SSL.SSL_CVERIFY_OPTIONAL, ReferenceCountedOpenSslContext.VERIFY_DEPTH);
-- break;
-- default:
-- throw new Error(mode.toString());
-- }
-- clientAuth = mode;
-- }
-- }
+-/**
+- * Implements a {@link SSLEngine} using
+- * <a href="https://www.openssl.org/docs/crypto/BIO_s_bio.html#EXAMPLE">OpenSSL BIO abstractions</a>.
+- * <p>Instances of this class must be {@link #release() released} or else native memory will leak!
+- *
+- * <p>Instances of this class <strong>must</strong> be released before the {@link ReferenceCountedOpenSslContext}
+- * the instance depends upon are released. Otherwise if any method of this class is called which uses the
+- * the {@link ReferenceCountedOpenSslContext} JNI resources the JVM may crash.
+- */
+-public class ReferenceCountedOpenSslEngine extends SSLEngine implements ReferenceCounted, ApplicationProtocolAccessor {
-
-- @Override
-- public final void setEnableSessionCreation(boolean b) {
-- if (b) {
-- throw new UnsupportedOperationException();
-- }
-- }
+- private static final InternalLogger logger = InternalLoggerFactory.getInstance(ReferenceCountedOpenSslEngine.class);
-
-- @Override
-- public final boolean getEnableSessionCreation() {
-- return false;
-- }
+- private static final ResourceLeakDetector<ReferenceCountedOpenSslEngine> leakDetector =
+- ResourceLeakDetectorFactory.instance().newResourceLeakDetector(ReferenceCountedOpenSslEngine.class);
+- private static final int OPENSSL_OP_NO_PROTOCOL_INDEX_SSLV2 = 0;
+- private static final int OPENSSL_OP_NO_PROTOCOL_INDEX_SSLV3 = 1;
+- private static final int OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1 = 2;
+- private static final int OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_1 = 3;
+- private static final int OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_2 = 4;
+- private static final int OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_3 = 5;
+- private static final int[] OPENSSL_OP_NO_PROTOCOLS = {
+- SSL.SSL_OP_NO_SSLv2,
+- SSL.SSL_OP_NO_SSLv3,
+- SSL.SSL_OP_NO_TLSv1,
+- SSL.SSL_OP_NO_TLSv1_1,
+- SSL.SSL_OP_NO_TLSv1_2,
+- SSL.SSL_OP_NO_TLSv1_3
+- };
-
-- @Override
-- public final synchronized SSLParameters getSSLParameters() {
-- SSLParameters sslParameters = super.getSSLParameters();
+- /**
+- * Depends upon tcnative ... only use if tcnative is available!
+- */
+- static final int MAX_PLAINTEXT_LENGTH = SSL.SSL_MAX_PLAINTEXT_LENGTH;
+- /**
+- * Depends upon tcnative ... only use if tcnative is available!
+- */
+- private static final int MAX_RECORD_SIZE = SSL.SSL_MAX_RECORD_LENGTH;
-
-- int version = PlatformDependent.javaVersion();
-- if (version >= 7) {
-- sslParameters.setEndpointIdentificationAlgorithm(endPointIdentificationAlgorithm);
-- Java7SslParametersUtils.setAlgorithmConstraints(sslParameters, algorithmConstraints);
-- if (version >= 8) {
-- if (sniHostNames != null) {
-- Java8SslUtils.setSniHostNames(sslParameters, sniHostNames);
-- }
-- if (!isDestroyed()) {
-- Java8SslUtils.setUseCipherSuitesOrder(
-- sslParameters, (SSL.getOptions(ssl) & SSL.SSL_OP_CIPHER_SERVER_PREFERENCE) != 0);
-- }
+- private static final SSLEngineResult NEED_UNWRAP_OK = new SSLEngineResult(OK, NEED_UNWRAP, 0, 0);
+- private static final SSLEngineResult NEED_UNWRAP_CLOSED = new SSLEngineResult(CLOSED, NEED_UNWRAP, 0, 0);
+- private static final SSLEngineResult NEED_WRAP_OK = new SSLEngineResult(OK, NEED_WRAP, 0, 0);
+- private static final SSLEngineResult NEED_WRAP_CLOSED = new SSLEngineResult(CLOSED, NEED_WRAP, 0, 0);
+- private static final SSLEngineResult CLOSED_NOT_HANDSHAKING = new SSLEngineResult(CLOSED, NOT_HANDSHAKING, 0, 0);
-
-- Java8SslUtils.setSNIMatchers(sslParameters, matchers);
-- }
-- }
-- return sslParameters;
+- // OpenSSL state
+- private long ssl;
+- private long networkBIO;
+-
+- private enum HandshakeState {
+- /**
+- * Not started yet.
+- */
+- NOT_STARTED,
+- /**
+- * Started via unwrap/wrap.
+- */
+- STARTED_IMPLICITLY,
+- /**
+- * Started via {@link #beginHandshake()}.
+- */
+- STARTED_EXPLICITLY,
+- /**
+- * Handshake is finished.
+- */
+- FINISHED
- }
-
-- @Override
-- public final synchronized void setSSLParameters(SSLParameters sslParameters) {
-- int version = PlatformDependent.javaVersion();
-- if (version >= 7) {
-- if (sslParameters.getAlgorithmConstraints() != null) {
-- throw new IllegalArgumentException("AlgorithmConstraints are not supported.");
-- }
+- private HandshakeState handshakeState = HandshakeState.NOT_STARTED;
+- private boolean receivedShutdown;
+- private volatile boolean destroyed;
+- private volatile String applicationProtocol;
+- private volatile boolean needTask;
-
-- if (version >= 8) {
-- if (!isDestroyed()) {
-- if (clientMode) {
-- final List<String> sniHostNames = Java8SslUtils.getSniHostNames(sslParameters);
-- for (String name: sniHostNames) {
-- SSL.setTlsExtHostName(ssl, name);
-- }
-- this.sniHostNames = sniHostNames;
-- }
-- if (Java8SslUtils.getUseCipherSuitesOrder(sslParameters)) {
-- SSL.setOptions(ssl, SSL.SSL_OP_CIPHER_SERVER_PREFERENCE);
-- } else {
-- SSL.clearOptions(ssl, SSL.SSL_OP_CIPHER_SERVER_PREFERENCE);
-- }
-- }
-- matchers = sslParameters.getSNIMatchers();
+- // Reference Counting
+- private final ResourceLeakTracker<ReferenceCountedOpenSslEngine> leak;
+- private final AbstractReferenceCounted refCnt = new AbstractReferenceCounted() {
+- @Override
+- public ReferenceCounted touch(Object hint) {
+- if (leak != null) {
+- leak.record(hint);
- }
-
-- final String endPointIdentificationAlgorithm = sslParameters.getEndpointIdentificationAlgorithm();
-- final boolean endPointVerificationEnabled = endPointIdentificationAlgorithm != null &&
-- !endPointIdentificationAlgorithm.isEmpty();
-- SSL.setHostNameValidation(ssl, DEFAULT_HOSTNAME_VALIDATION_FLAGS,
-- endPointVerificationEnabled ? getPeerHost() : null);
-- // If the user asks for hostname verification we must ensure we verify the peer.
-- // If the user disables hostname verification we leave it up to the user to change the mode manually.
-- if (clientMode && endPointVerificationEnabled) {
-- SSL.setVerify(ssl, SSL.SSL_CVERIFY_REQUIRED, -1);
-- }
+- return ReferenceCountedOpenSslEngine.this;
+- }
-
-- this.endPointIdentificationAlgorithm = endPointIdentificationAlgorithm;
-- algorithmConstraints = sslParameters.getAlgorithmConstraints();
+- @Override
+- protected void deallocate() {
+- shutdown();
+- if (leak != null) {
+- boolean closed = leak.close(ReferenceCountedOpenSslEngine.this);
+- assert closed;
+- }
+- parentContext.release();
- }
-- super.setSSLParameters(sslParameters);
-- }
+- };
-
-- private boolean isDestroyed() {
-- return destroyed != 0;
-- }
+- private volatile ClientAuth clientAuth = ClientAuth.NONE;
+- private volatile Certificate[] localCertificateChain;
-
-- static int calculateOutNetBufSize(int pendingBytes, int numComponents) {
-- return (int) min(MAX_ENCRYPTED_PACKET_LENGTH,
-- pendingBytes + (long) MAX_TLS_RECORD_OVERHEAD_LENGTH * numComponents);
-- }
+- // Updated once a new handshake is started and so the SSLSession reused.
+- private volatile long lastAccessed = -1;
-
-- final boolean checkSniHostnameMatch(String hostname) {
-- return Java8SslUtils.checkSniHostnameMatch(matchers, hostname);
-- }
+- private String endPointIdentificationAlgorithm;
+- // Store as object as AlgorithmConstraints only exists since java 7.
+- private Object algorithmConstraints;
+- private List<String> sniHostNames;
-
-- private final class OpenSslSession implements SSLSession, ApplicationProtocolAccessor {
-- private final OpenSslSessionContext sessionContext;
+- // Mark as volatile as accessed by checkSniHostnameMatch(...) and also not specify the SNIMatcher type to allow us
+- // using it with java7.
+- private volatile Collection<?> matchers;
-
-- // These are guarded by synchronized(OpenSslEngine.this) as handshakeFinished() may be triggered by any
-- // thread.
-- private X509Certificate[] x509PeerCerts;
-- private Certificate[] peerCerts;
-- private String protocol;
-- private String applicationProtocol;
-- private String cipher;
-- private byte[] id;
-- private long creationTime;
+- // SSL Engine status variables
+- private boolean isInboundDone;
+- private boolean outboundClosed;
-
-- // lazy init for memory reasons
-- private Map<String, Object> values;
+- final boolean jdkCompatibilityMode;
+- private final boolean clientMode;
+- final ByteBufAllocator alloc;
+- private final OpenSslEngineMap engineMap;
+- private final OpenSslApplicationProtocolNegotiator apn;
+- private final ReferenceCountedOpenSslContext parentContext;
+- private final OpenSslSession session;
+- private final ByteBuffer[] singleSrcBuffer = new ByteBuffer[1];
+- private final ByteBuffer[] singleDstBuffer = new ByteBuffer[1];
+- private final boolean enableOcsp;
+- private int maxWrapOverhead;
+- private int maxWrapBufferSize;
+- private Throwable pendingException;
-
-- OpenSslSession(OpenSslSessionContext sessionContext) {
-- this.sessionContext = sessionContext;
-- }
+- /**
+- * Create a new instance.
+- * @param context Reference count release responsibility is not transferred! The callee still owns this object.
+- * @param alloc The allocator to use.
+- * @param peerHost The peer host name.
+- * @param peerPort The peer port.
+- * @param jdkCompatibilityMode {@code true} to behave like described in
+- * https://docs.oracle.com/javase/7/docs/api/javax/net/ssl/SSLEngine.html.
+- * {@code false} allows for partial and/or multiple packets to be process in a single
+- * wrap or unwrap call.
+- * @param leakDetection {@code true} to enable leak detection of this object.
+- */
+- ReferenceCountedOpenSslEngine(ReferenceCountedOpenSslContext context, final ByteBufAllocator alloc, String peerHost,
+- int peerPort, boolean jdkCompatibilityMode, boolean leakDetection) {
+- super(peerHost, peerPort);
+- OpenSsl.ensureAvailability();
+- this.alloc = checkNotNull(alloc, "alloc");
+- apn = (OpenSslApplicationProtocolNegotiator) context.applicationProtocolNegotiator();
+- clientMode = context.isClient();
+- if (PlatformDependent.javaVersion() >= 7) {
+- session = new ExtendedOpenSslSession(new DefaultOpenSslSession(context.sessionContext())) {
+- private String[] peerSupportedSignatureAlgorithms;
+- private List requestedServerNames;
-
-- @Override
-- public byte[] getId() {
-- synchronized (ReferenceCountedOpenSslEngine.this) {
-- if (id == null) {
-- return EmptyArrays.EMPTY_BYTES;
+- @Override
+- public List getRequestedServerNames() {
+- if (clientMode) {
+- return Java8SslUtils.getSniHostNames(sniHostNames);
+- } else {
+- synchronized (ReferenceCountedOpenSslEngine.this) {
+- if (requestedServerNames == null) {
+- if (isDestroyed()) {
+- requestedServerNames = Collections.emptyList();
+- } else {
+- String name = SSL.getSniHostname(ssl);
+- if (name == null) {
+- requestedServerNames = Collections.emptyList();
+- } else {
+- // Convert to bytes as we do not want to do any strict validation of the
+- // SNIHostName while creating it.
+- requestedServerNames =
+- Java8SslUtils.getSniHostName(
+- SSL.getSniHostname(ssl).getBytes(CharsetUtil.UTF_8));
+- }
+- }
+- }
+- return requestedServerNames;
+- }
+- }
- }
-- return id.clone();
-- }
-- }
-
-- @Override
-- public SSLSessionContext getSessionContext() {
-- return sessionContext;
-- }
+- @Override
+- public String[] getPeerSupportedSignatureAlgorithms() {
+- synchronized (ReferenceCountedOpenSslEngine.this) {
+- if (peerSupportedSignatureAlgorithms == null) {
+- if (isDestroyed()) {
+- peerSupportedSignatureAlgorithms = EmptyArrays.EMPTY_STRINGS;
+- } else {
+- String[] algs = SSL.getSigAlgs(ssl);
+- if (algs == null) {
+- peerSupportedSignatureAlgorithms = EmptyArrays.EMPTY_STRINGS;
+- } else {
+- Set<String> algorithmList = new LinkedHashSet<String>(algs.length);
+- for (String alg: algs) {
+- String converted = SignatureAlgorithmConverter.toJavaName(alg);
-
-- @Override
-- public long getCreationTime() {
-- synchronized (ReferenceCountedOpenSslEngine.this) {
-- if (creationTime == 0 && !isDestroyed()) {
-- creationTime = SSL.getTime(ssl) * 1000L;
+- if (converted != null) {
+- algorithmList.add(converted);
+- }
+- }
+- peerSupportedSignatureAlgorithms = algorithmList.toArray(new String[0]);
+- }
+- }
+- }
+- return peerSupportedSignatureAlgorithms.clone();
+- }
- }
-- }
-- return creationTime;
-- }
--
-- @Override
-- public long getLastAccessedTime() {
-- long lastAccessed = ReferenceCountedOpenSslEngine.this.lastAccessed;
-- // if lastAccessed is -1 we will just return the creation time as the handshake was not started yet.
-- return lastAccessed == -1 ? getCreationTime() : lastAccessed;
-- }
-
-- @Override
-- public void invalidate() {
-- synchronized (ReferenceCountedOpenSslEngine.this) {
-- if (!isDestroyed()) {
-- SSL.setTimeout(ssl, 0);
+- @Override
+- public List<byte[]> getStatusResponses() {
+- byte[] ocspResponse = null;
+- if (enableOcsp && clientMode) {
+- synchronized (ReferenceCountedOpenSslEngine.this) {
+- if (!isDestroyed()) {
+- ocspResponse = SSL.getOcspResponse(ssl);
+- }
+- }
+- }
+- return ocspResponse == null ?
+- Collections.<byte[]>emptyList() : Collections.singletonList(ocspResponse);
- }
-- }
+- };
+- } else {
+- session = new DefaultOpenSslSession(context.sessionContext());
- }
--
-- @Override
-- public boolean isValid() {
-- synchronized (ReferenceCountedOpenSslEngine.this) {
-- if (!isDestroyed()) {
-- return System.currentTimeMillis() - (SSL.getTimeout(ssl) * 1000L) < (SSL.getTime(ssl) * 1000L);
-- }
-- }
-- return false;
+- engineMap = context.engineMap;
+- enableOcsp = context.enableOcsp;
+- if (!context.sessionContext().useKeyManager()) {
+- // If we do not use the KeyManagerFactory we need to set localCertificateChain now.
+- // When we use a KeyManagerFactory it will be set during setKeyMaterial(...).
+- localCertificateChain = context.keyCertChain;
- }
-
-- @Override
-- public void putValue(String name, Object value) {
-- if (name == null) {
-- throw new NullPointerException("name");
-- }
-- if (value == null) {
-- throw new NullPointerException("value");
-- }
-- Map<String, Object> values = this.values;
-- if (values == null) {
-- // Use size of 2 to keep the memory overhead small
-- values = this.values = new HashMap<String, Object>(2);
-- }
-- Object old = values.put(name, value);
-- if (value instanceof SSLSessionBindingListener) {
-- ((SSLSessionBindingListener) value).valueBound(new SSLSessionBindingEvent(this, name));
-- }
-- notifyUnbound(old, name);
+- this.jdkCompatibilityMode = jdkCompatibilityMode;
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- final long finalSsl;
+- try {
+- finalSsl = SSL.newSSL(context.ctx, !context.isClient());
+- } finally {
+- readerLock.unlock();
- }
+- synchronized (this) {
+- ssl = finalSsl;
+- try {
+- networkBIO = SSL.bioNewByteBuffer(ssl, context.getBioNonApplicationBufferSize());
-
-- @Override
-- public Object getValue(String name) {
-- if (name == null) {
-- throw new NullPointerException("name");
-- }
-- if (values == null) {
-- return null;
-- }
-- return values.get(name);
-- }
+- // Set the client auth mode, this needs to be done via setClientAuth(...) method so we actually call the
+- // needed JNI methods.
+- setClientAuth(clientMode ? ClientAuth.NONE : context.clientAuth);
-
-- @Override
-- public void removeValue(String name) {
-- if (name == null) {
-- throw new NullPointerException("name");
-- }
-- Map<String, Object> values = this.values;
-- if (values == null) {
-- return;
-- }
-- Object old = values.remove(name);
-- notifyUnbound(old, name);
-- }
+- if (context.protocols != null) {
+- setEnabledProtocols(context.protocols);
+- }
-
-- @Override
-- public String[] getValueNames() {
-- Map<String, Object> values = this.values;
-- if (values == null || values.isEmpty()) {
-- return EmptyArrays.EMPTY_STRINGS;
-- }
-- return values.keySet().toArray(new String[values.size()]);
-- }
+- // Use SNI if peerHost was specified and a valid hostname
+- // See https://github.com/netty/netty/issues/4746
+- if (clientMode && SslUtils.isValidHostNameForSNI(peerHost)) {
+- SSL.setTlsExtHostName(ssl, peerHost);
+- sniHostNames = Collections.singletonList(peerHost);
+- }
-
-- private void notifyUnbound(Object value, String name) {
-- if (value instanceof SSLSessionBindingListener) {
-- ((SSLSessionBindingListener) value).valueUnbound(new SSLSessionBindingEvent(this, name));
-- }
-- }
+- if (enableOcsp) {
+- SSL.enableOcsp(ssl);
+- }
-
-- /**
-- * Finish the handshake and so init everything in the {@link OpenSslSession} that should be accessible by
-- * the user.
-- */
-- void handshakeFinished() throws SSLException {
-- synchronized (ReferenceCountedOpenSslEngine.this) {
-- if (!isDestroyed()) {
-- id = SSL.getSessionId(ssl);
-- cipher = toJavaCipherSuite(SSL.getCipherForSSL(ssl));
-- protocol = SSL.getVersion(ssl);
+- if (!jdkCompatibilityMode) {
+- SSL.setMode(ssl, SSL.getMode(ssl) | SSL.SSL_MODE_ENABLE_PARTIAL_WRITE);
+- }
-
-- initPeerCerts();
-- selectApplicationProtocol();
+- // setMode may impact the overhead.
+- calculateMaxWrapOverhead();
+- } catch (Throwable cause) {
+- // Call shutdown so we are sure we correctly release all native memory and also guard against the
+- // case when shutdown() will be called by the finalizer again.
+- shutdown();
-
-- handshakeState = HandshakeState.FINISHED;
-- } else {
-- throw new SSLException("Already closed");
-- }
+- PlatformDependent.throwException(cause);
- }
- }
-
-- /**
-- * Init peer certificates that can be obtained via {@link #getPeerCertificateChain()}
-- * and {@link #getPeerCertificates()}.
-- */
-- private void initPeerCerts() {
-- // Return the full chain from the JNI layer.
-- byte[][] chain = SSL.getPeerCertChain(ssl);
-- if (clientMode) {
-- if (isEmpty(chain)) {
-- peerCerts = EMPTY_CERTIFICATES;
-- x509PeerCerts = EMPTY_JAVAX_X509_CERTIFICATES;
-- } else {
-- peerCerts = new Certificate[chain.length];
-- x509PeerCerts = new X509Certificate[chain.length];
-- initCerts(chain, 0);
-- }
-- } else {
-- // if used on the server side SSL_get_peer_cert_chain(...) will not include the remote peer
-- // certificate. We use SSL_get_peer_certificate to get it in this case and add it to our
-- // array later.
-- //
-- // See https://www.openssl.org/docs/ssl/SSL_get_peer_cert_chain.html
-- byte[] clientCert = SSL.getPeerCertificate(ssl);
-- if (isEmpty(clientCert)) {
-- peerCerts = EMPTY_CERTIFICATES;
-- x509PeerCerts = EMPTY_JAVAX_X509_CERTIFICATES;
-- } else {
-- if (isEmpty(chain)) {
-- peerCerts = new Certificate[] {new OpenSslX509Certificate(clientCert)};
-- x509PeerCerts = new X509Certificate[] {new OpenSslJavaxX509Certificate(clientCert)};
-- } else {
-- peerCerts = new Certificate[chain.length + 1];
-- x509PeerCerts = new X509Certificate[chain.length + 1];
-- peerCerts[0] = new OpenSslX509Certificate(clientCert);
-- x509PeerCerts[0] = new OpenSslJavaxX509Certificate(clientCert);
-- initCerts(chain, 1);
-- }
-- }
-- }
+- // Now that everything looks good and we're going to successfully return the
+- // object so we need to retain a reference to the parent context.
+- parentContext = context;
+- parentContext.retain();
+-
+- // Only create the leak after everything else was executed and so ensure we don't produce a false-positive for
+- // the ResourceLeakDetector.
+- leak = leakDetection ? leakDetector.track(this) : null;
+- }
+-
+- final synchronized String[] authMethods() {
+- if (isDestroyed()) {
+- return EmptyArrays.EMPTY_STRINGS;
- }
+- return SSL.authenticationMethods(ssl);
+- }
-
-- private void initCerts(byte[][] chain, int startPos) {
-- for (int i = 0; i < chain.length; i++) {
-- int certPos = startPos + i;
-- peerCerts[certPos] = new OpenSslX509Certificate(chain[i]);
-- x509PeerCerts[certPos] = new OpenSslJavaxX509Certificate(chain[i]);
+- final boolean setKeyMaterial(OpenSslKeyMaterial keyMaterial) throws Exception {
+- synchronized (this) {
+- if (isDestroyed()) {
+- return false;
- }
+- SSL.setKeyMaterial(ssl, keyMaterial.certificateChainAddress(), keyMaterial.privateKeyAddress());
- }
+- localCertificateChain = keyMaterial.certificateChain();
+- return true;
+- }
-
-- /**
-- * Select the application protocol used.
-- */
-- private void selectApplicationProtocol() throws SSLException {
-- ApplicationProtocolConfig.SelectedListenerFailureBehavior behavior = apn.selectedListenerFailureBehavior();
-- List<String> protocols = apn.protocols();
-- String applicationProtocol;
-- switch (apn.protocol()) {
-- case NONE:
-- break;
-- // We always need to check for applicationProtocol == null as the remote peer may not support
-- // the TLS extension or may have returned an empty selection.
-- case ALPN:
-- applicationProtocol = SSL.getAlpnSelected(ssl);
-- if (applicationProtocol != null) {
-- this.applicationProtocol = selectApplicationProtocol(
-- protocols, behavior, applicationProtocol);
-- }
-- break;
-- case NPN:
-- applicationProtocol = SSL.getNextProtoNegotiated(ssl);
-- if (applicationProtocol != null) {
-- this.applicationProtocol = selectApplicationProtocol(
-- protocols, behavior, applicationProtocol);
-- }
-- break;
-- case NPN_AND_ALPN:
-- applicationProtocol = SSL.getAlpnSelected(ssl);
-- if (applicationProtocol == null) {
-- applicationProtocol = SSL.getNextProtoNegotiated(ssl);
-- }
-- if (applicationProtocol != null) {
-- this.applicationProtocol = selectApplicationProtocol(
-- protocols, behavior, applicationProtocol);
-- }
-- break;
-- default:
-- throw new Error();
-- }
+- final synchronized SecretKeySpec masterKey() {
+- if (isDestroyed()) {
+- return null;
- }
+- return new SecretKeySpec(SSL.getMasterKey(ssl), "AES");
+- }
-
-- private String selectApplicationProtocol(List<String> protocols,
-- ApplicationProtocolConfig.SelectedListenerFailureBehavior behavior,
-- String applicationProtocol) throws SSLException {
-- if (behavior == ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT) {
-- return applicationProtocol;
-- } else {
-- int size = protocols.size();
-- assert size > 0;
-- if (protocols.contains(applicationProtocol)) {
-- return applicationProtocol;
-- } else {
-- if (behavior == ApplicationProtocolConfig.SelectedListenerFailureBehavior.CHOOSE_MY_LAST_PROTOCOL) {
-- return protocols.get(size - 1);
-- } else {
-- throw new SSLException("unknown protocol " + applicationProtocol);
-- }
-- }
+- /**
+- * Sets the OCSP response.
+- */
+- @UnstableApi
+- public void setOcspResponse(byte[] response) {
+- if (!enableOcsp) {
+- throw new IllegalStateException("OCSP stapling is not enabled");
+- }
+-
+- if (clientMode) {
+- throw new IllegalStateException("Not a server SSLEngine");
+- }
+-
+- synchronized (this) {
+- if (!isDestroyed()) {
+- SSL.setOcspResponse(ssl, response);
- }
- }
+- }
-
-- @Override
-- public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException {
-- synchronized (ReferenceCountedOpenSslEngine.this) {
-- if (isEmpty(peerCerts)) {
-- throw new SSLPeerUnverifiedException("peer not verified");
-- }
-- return peerCerts.clone();
+- /**
+- * Returns the OCSP response or {@code null} if the server didn't provide a stapled OCSP response.
+- */
+- @UnstableApi
+- public byte[] getOcspResponse() {
+- if (!enableOcsp) {
+- throw new IllegalStateException("OCSP stapling is not enabled");
+- }
+-
+- if (!clientMode) {
+- throw new IllegalStateException("Not a client SSLEngine");
+- }
+-
+- synchronized (this) {
+- if (isDestroyed()) {
+- return EmptyArrays.EMPTY_BYTES;
- }
+- return SSL.getOcspResponse(ssl);
- }
+- }
-
-- @Override
-- public Certificate[] getLocalCertificates() {
-- if (localCerts == null) {
+- @Override
+- public final int refCnt() {
+- return refCnt.refCnt();
+- }
+-
+- @Override
+- public final ReferenceCounted retain() {
+- refCnt.retain();
+- return this;
+- }
+-
+- @Override
+- public final ReferenceCounted retain(int increment) {
+- refCnt.retain(increment);
+- return this;
+- }
+-
+- @Override
+- public final ReferenceCounted touch() {
+- refCnt.touch();
+- return this;
+- }
+-
+- @Override
+- public final ReferenceCounted touch(Object hint) {
+- refCnt.touch(hint);
+- return this;
+- }
+-
+- @Override
+- public final boolean release() {
+- return refCnt.release();
+- }
+-
+- @Override
+- public final boolean release(int decrement) {
+- return refCnt.release(decrement);
+- }
+-
+- @Override
+- public final synchronized SSLSession getHandshakeSession() {
+- // Javadocs state return value should be:
+- // null if this instance is not currently handshaking, or if the current handshake has not
+- // progressed far enough to create a basic SSLSession. Otherwise, this method returns the
+- // SSLSession currently being negotiated.
+- switch(handshakeState) {
+- case NOT_STARTED:
+- case FINISHED:
- return null;
-- }
-- return localCerts.clone();
+- default:
+- return session;
- }
+- }
-
-- @Override
-- public X509Certificate[] getPeerCertificateChain() throws SSLPeerUnverifiedException {
-- synchronized (ReferenceCountedOpenSslEngine.this) {
-- if (isEmpty(x509PeerCerts)) {
-- throw new SSLPeerUnverifiedException("peer not verified");
+- /**
+- * Returns the pointer to the {@code SSL} object for this {@link ReferenceCountedOpenSslEngine}.
+- * Be aware that it is freed as soon as the {@link #release()} or {@link #shutdown()} methods are called.
+- * At this point {@code 0} will be returned.
+- */
+- public final synchronized long sslPointer() {
+- return ssl;
+- }
+-
+- /**
+- * Destroys this engine.
+- */
+- public final synchronized void shutdown() {
+- if (!destroyed) {
+- destroyed = true;
+- engineMap.remove(ssl);
+- SSL.freeSSL(ssl);
+- ssl = networkBIO = 0;
+-
+- isInboundDone = outboundClosed = true;
+- }
+-
+- // On shutdown clear all errors
+- SSL.clearError();
+- }
+-
+- /**
+- * Write plaintext data to the OpenSSL internal BIO
+- *
+- * Calling this function with src.remaining == 0 is undefined.
+- */
+- private int writePlaintextData(final ByteBuffer src, int len) {
+- final int pos = src.position();
+- final int limit = src.limit();
+- final int sslWrote;
+-
+- if (src.isDirect()) {
+- sslWrote = SSL.writeToSSL(ssl, bufferAddress(src) + pos, len);
+- if (sslWrote > 0) {
+- src.position(pos + sslWrote);
+- }
+- } else {
+- ByteBuf buf = alloc.directBuffer(len);
+- try {
+- src.limit(pos + len);
+-
+- buf.setBytes(0, src);
+- src.limit(limit);
+-
+- sslWrote = SSL.writeToSSL(ssl, memoryAddress(buf), len);
+- if (sslWrote > 0) {
+- src.position(pos + sslWrote);
+- } else {
+- src.position(pos);
- }
-- return x509PeerCerts.clone();
+- } finally {
+- buf.release();
- }
- }
+- return sslWrote;
+- }
-
-- @Override
-- public Principal getPeerPrincipal() throws SSLPeerUnverifiedException {
-- Certificate[] peer = getPeerCertificates();
-- // No need for null or length > 0 is needed as this is done in getPeerCertificates()
-- // already.
-- return ((java.security.cert.X509Certificate) peer[0]).getSubjectX500Principal();
-- }
+- /**
+- * Write encrypted data to the OpenSSL network BIO.
+- */
+- private ByteBuf writeEncryptedData(final ByteBuffer src, int len) {
+- final int pos = src.position();
+- if (src.isDirect()) {
+- SSL.bioSetByteBuffer(networkBIO, bufferAddress(src) + pos, len, false);
+- } else {
+- final ByteBuf buf = alloc.directBuffer(len);
+- try {
+- final int limit = src.limit();
+- src.limit(pos + len);
+- buf.writeBytes(src);
+- // Restore the original position and limit because we don't want to consume from `src`.
+- src.position(pos);
+- src.limit(limit);
-
-- @Override
-- public Principal getLocalPrincipal() {
-- Certificate[] local = localCerts;
-- if (local == null || local.length == 0) {
-- return null;
+- SSL.bioSetByteBuffer(networkBIO, memoryAddress(buf), len, false);
+- return buf;
+- } catch (Throwable cause) {
+- buf.release();
+- PlatformDependent.throwException(cause);
- }
-- return ((java.security.cert.X509Certificate) local[0]).getIssuerX500Principal();
- }
+- return null;
+- }
-
-- @Override
-- public String getCipherSuite() {
-- synchronized (ReferenceCountedOpenSslEngine.this) {
-- if (cipher == null) {
-- return INVALID_CIPHER;
-- }
-- return cipher;
+- /**
+- * Read plaintext data from the OpenSSL internal BIO
+- */
+- private int readPlaintextData(final ByteBuffer dst) {
+- final int sslRead;
+- final int pos = dst.position();
+- if (dst.isDirect()) {
+- sslRead = SSL.readFromSSL(ssl, bufferAddress(dst) + pos, dst.limit() - pos);
+- if (sslRead > 0) {
+- dst.position(pos + sslRead);
- }
-- }
--
-- @Override
-- public String getProtocol() {
-- String protocol = this.protocol;
-- if (protocol == null) {
-- synchronized (ReferenceCountedOpenSslEngine.this) {
-- if (!isDestroyed()) {
-- protocol = SSL.getVersion(ssl);
-- } else {
-- protocol = StringUtil.EMPTY_STRING;
-- }
+- } else {
+- final int limit = dst.limit();
+- final int len = min(maxEncryptedPacketLength0(), limit - pos);
+- final ByteBuf buf = alloc.directBuffer(len);
+- try {
+- sslRead = SSL.readFromSSL(ssl, memoryAddress(buf), len);
+- if (sslRead > 0) {
+- dst.limit(pos + sslRead);
+- buf.getBytes(buf.readerIndex(), dst);
+- dst.limit(limit);
- }
+- } finally {
+- buf.release();
- }
-- return protocol;
-- }
--
-- @Override
-- public String getApplicationProtocol() {
-- synchronized (ReferenceCountedOpenSslEngine.this) {
-- return applicationProtocol;
-- }
-- }
--
-- @Override
-- public String getPeerHost() {
-- return ReferenceCountedOpenSslEngine.this.getPeerHost();
- }
-
-- @Override
-- public int getPeerPort() {
-- return ReferenceCountedOpenSslEngine.this.getPeerPort();
-- }
+- return sslRead;
+- }
-
-- @Override
-- public int getPacketBufferSize() {
-- return MAX_ENCRYPTED_PACKET_LENGTH;
-- }
+- /**
+- * Visible only for testing!
+- */
+- final synchronized int maxWrapOverhead() {
+- return maxWrapOverhead;
+- }
-
-- @Override
-- public int getApplicationBufferSize() {
-- return MAX_PLAINTEXT_LENGTH;
-- }
+- /**
+- * Visible only for testing!
+- */
+- final synchronized int maxEncryptedPacketLength() {
+- return maxEncryptedPacketLength0();
- }
--}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslServerContext.java b/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslServerContext.java
-deleted file mode 100644
-index 4c9df31..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslServerContext.java
-+++ /dev/null
-@@ -1,239 +0,0 @@
--/*
-- * Copyright 2016 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
-
--import io.netty.internal.tcnative.SSL;
--import io.netty.internal.tcnative.SSLContext;
--import io.netty.internal.tcnative.SniHostNameMatcher;
--import io.netty.util.internal.PlatformDependent;
--import io.netty.util.internal.logging.InternalLogger;
--import io.netty.util.internal.logging.InternalLoggerFactory;
+- /**
+- * This method is intentionally not synchronized, only use if you know you are in the EventLoop
+- * thread and visibility on {@link #maxWrapOverhead} is achieved via other synchronized blocks.
+- */
+- final int maxEncryptedPacketLength0() {
+- return maxWrapOverhead + MAX_PLAINTEXT_LENGTH;
+- }
-
--import java.security.KeyStore;
--import java.security.PrivateKey;
--import java.security.cert.X509Certificate;
--import javax.net.ssl.KeyManagerFactory;
--import javax.net.ssl.SSLException;
--import javax.net.ssl.TrustManagerFactory;
--import javax.net.ssl.X509ExtendedKeyManager;
--import javax.net.ssl.X509ExtendedTrustManager;
--import javax.net.ssl.X509KeyManager;
--import javax.net.ssl.X509TrustManager;
+- /**
+- * This method is intentionally not synchronized, only use if you know you are in the EventLoop
+- * thread and visibility on {@link #maxWrapBufferSize} and {@link #maxWrapOverhead} is achieved
+- * via other synchronized blocks.
+- */
+- final int calculateMaxLengthForWrap(int plaintextLength, int numComponents) {
+- return (int) min(maxWrapBufferSize, plaintextLength + (long) maxWrapOverhead * numComponents);
+- }
-
--import static io.netty.util.internal.ObjectUtil.checkNotNull;
+- final synchronized int sslPending() {
+- return sslPending0();
+- }
-
--/**
-- * A server-side {@link SslContext} which uses OpenSSL's SSL/TLS implementation.
-- * <p>Instances of this class must be {@link #release() released} or else native memory will leak!
-- *
-- * <p>Instances of this class <strong>must not</strong> be released before any {@link ReferenceCountedOpenSslEngine}
-- * which depends upon the instance of this class is released. Otherwise if any method of
-- * {@link ReferenceCountedOpenSslEngine} is called which uses this class's JNI resources the JVM may crash.
-- */
--public final class ReferenceCountedOpenSslServerContext extends ReferenceCountedOpenSslContext {
-- private static final InternalLogger logger =
-- InternalLoggerFactory.getInstance(ReferenceCountedOpenSslServerContext.class);
-- private static final byte[] ID = {'n', 'e', 't', 't', 'y'};
-- private final OpenSslServerSessionContext sessionContext;
-- private final OpenSslKeyMaterialManager keyMaterialManager;
+- /**
+- * It is assumed this method is called in a synchronized block (or the constructor)!
+- */
+- private void calculateMaxWrapOverhead() {
+- maxWrapOverhead = SSL.getMaxWrapOverhead(ssl);
-
-- ReferenceCountedOpenSslServerContext(
-- X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory,
-- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory,
-- Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
-- long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[] protocols, boolean startTls,
-- boolean enableOcsp) throws SSLException {
-- this(trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory, ciphers,
-- cipherFilter, toNegotiator(apn), sessionCacheSize, sessionTimeout, clientAuth, protocols, startTls,
-- enableOcsp);
+- // maxWrapBufferSize must be set after maxWrapOverhead because there is a dependency on this value.
+- // If jdkCompatibility mode is off we allow enough space to encrypt 16 buffers at a time. This could be
+- // configurable in the future if necessary.
+- maxWrapBufferSize = jdkCompatibilityMode ? maxEncryptedPacketLength0() : maxEncryptedPacketLength0() << 4;
- }
-
-- private ReferenceCountedOpenSslServerContext(
-- X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory,
-- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory,
-- Iterable<String> ciphers, CipherSuiteFilter cipherFilter, OpenSslApplicationProtocolNegotiator apn,
-- long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[] protocols, boolean startTls,
-- boolean enableOcsp) throws SSLException {
-- super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, SSL.SSL_MODE_SERVER, keyCertChain,
-- clientAuth, protocols, startTls, enableOcsp, true);
-- // Create a new SSL_CTX and configure it.
-- boolean success = false;
-- try {
-- ServerContext context = newSessionContext(this, ctx, engineMap, trustCertCollection, trustManagerFactory,
-- keyCertChain, key, keyPassword, keyManagerFactory);
-- sessionContext = context.sessionContext;
-- keyMaterialManager = context.keyMaterialManager;
-- success = true;
-- } finally {
-- if (!success) {
-- release();
-- }
-- }
+- private int sslPending0() {
+- // OpenSSL has a limitation where if you call SSL_pending before the handshake is complete OpenSSL will throw a
+- // "called a function you should not call" error. Using the TLS_method instead of SSLv23_method may solve this
+- // issue but this API is only available in 1.1.0+ [1].
+- // [1] https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_new.html
+- return handshakeState != HandshakeState.FINISHED ? 0 : SSL.sslPending(ssl);
- }
-
-- @Override
-- public OpenSslServerSessionContext sessionContext() {
-- return sessionContext;
+- private boolean isBytesAvailableEnoughForWrap(int bytesAvailable, int plaintextLength, int numComponents) {
+- return bytesAvailable - (long) maxWrapOverhead * numComponents >= plaintextLength;
- }
-
- @Override
-- OpenSslKeyMaterialManager keyMaterialManager() {
-- return keyMaterialManager;
-- }
+- public final SSLEngineResult wrap(
+- final ByteBuffer[] srcs, int offset, final int length, final ByteBuffer dst) throws SSLException {
+- // Throw required runtime exceptions
+- if (srcs == null) {
+- throw new IllegalArgumentException("srcs is null");
+- }
+- if (dst == null) {
+- throw new IllegalArgumentException("dst is null");
+- }
-
-- static final class ServerContext {
-- OpenSslServerSessionContext sessionContext;
-- OpenSslKeyMaterialManager keyMaterialManager;
-- }
+- if (offset >= srcs.length || offset + length > srcs.length) {
+- throw new IndexOutOfBoundsException(
+- "offset: " + offset + ", length: " + length +
+- " (expected: offset <= offset + length <= srcs.length (" + srcs.length + "))");
+- }
-
-- static ServerContext newSessionContext(ReferenceCountedOpenSslContext thiz, long ctx, OpenSslEngineMap engineMap,
-- X509Certificate[] trustCertCollection,
-- TrustManagerFactory trustManagerFactory,
-- X509Certificate[] keyCertChain, PrivateKey key,
-- String keyPassword, KeyManagerFactory keyManagerFactory)
-- throws SSLException {
-- ServerContext result = new ServerContext();
-- try {
-- SSLContext.setVerify(ctx, SSL.SSL_CVERIFY_NONE, VERIFY_DEPTH);
-- if (!OpenSsl.useKeyManagerFactory()) {
-- if (keyManagerFactory != null) {
-- throw new IllegalArgumentException(
-- "KeyManagerFactory not supported");
+- if (dst.isReadOnly()) {
+- throw new ReadOnlyBufferException();
+- }
+-
+- synchronized (this) {
+- if (isOutboundDone()) {
+- // All drained in the outbound buffer
+- return isInboundDone() || isDestroyed() ? CLOSED_NOT_HANDSHAKING : NEED_UNWRAP_CLOSED;
+- }
+-
+- int bytesProduced = 0;
+- ByteBuf bioReadCopyBuf = null;
+- try {
+- // Setup the BIO buffer so that we directly write the encryption results into dst.
+- if (dst.isDirect()) {
+- SSL.bioSetByteBuffer(networkBIO, bufferAddress(dst) + dst.position(), dst.remaining(),
+- true);
+- } else {
+- bioReadCopyBuf = alloc.directBuffer(dst.remaining());
+- SSL.bioSetByteBuffer(networkBIO, memoryAddress(bioReadCopyBuf), bioReadCopyBuf.writableBytes(),
+- true);
+- }
+-
+- int bioLengthBefore = SSL.bioLengthByteBuffer(networkBIO);
+-
+- // Explicitly use outboundClosed as we want to drain any bytes that are still present.
+- if (outboundClosed) {
+- // If the outbound was closed we want to ensure we can produce the alert to the destination buffer.
+- // This is true even if we not using jdkCompatibilityMode.
+- //
+- // We use a plaintextLength of 2 as we at least want to have an alert fit into it.
+- // https://tools.ietf.org/html/rfc5246#section-7.2
+- if (!isBytesAvailableEnoughForWrap(dst.remaining(), 2, 1)) {
+- return new SSLEngineResult(BUFFER_OVERFLOW, getHandshakeStatus(), 0, 0);
+- }
+-
+- // There is something left to drain.
+- // See https://github.com/netty/netty/issues/6260
+- bytesProduced = SSL.bioFlushByteBuffer(networkBIO);
+- if (bytesProduced <= 0) {
+- return newResultMayFinishHandshake(NOT_HANDSHAKING, 0, 0);
+- }
+- // It is possible when the outbound was closed there was not enough room in the non-application
+- // buffers to hold the close_notify. We should keep trying to close until we consume all the data
+- // OpenSSL can give us.
+- if (!doSSLShutdown()) {
+- return newResultMayFinishHandshake(NOT_HANDSHAKING, 0, bytesProduced);
+- }
+- bytesProduced = bioLengthBefore - SSL.bioLengthByteBuffer(networkBIO);
+- return newResultMayFinishHandshake(NEED_WRAP, 0, bytesProduced);
- }
-- checkNotNull(keyCertChain, "keyCertChain");
-
-- setKeyMaterial(ctx, keyCertChain, key, keyPassword);
-- } else {
-- // javadocs state that keyManagerFactory has precedent over keyCertChain, and we must have a
-- // keyManagerFactory for the server so build one if it is not specified.
-- if (keyManagerFactory == null) {
-- keyManagerFactory = buildKeyManagerFactory(
-- keyCertChain, key, keyPassword, keyManagerFactory);
-- }
-- X509KeyManager keyManager = chooseX509KeyManager(keyManagerFactory.getKeyManagers());
-- result.keyMaterialManager = useExtendedKeyManager(keyManager) ?
-- new OpenSslExtendedKeyMaterialManager(
-- (X509ExtendedKeyManager) keyManager, keyPassword) :
-- new OpenSslKeyMaterialManager(keyManager, keyPassword);
-- }
-- } catch (Exception e) {
-- throw new SSLException("failed to set certificate and key", e);
-- }
-- try {
-- if (trustCertCollection != null) {
-- trustManagerFactory = buildTrustManagerFactory(trustCertCollection, trustManagerFactory);
-- } else if (trustManagerFactory == null) {
-- // Mimic the way SSLContext.getInstance(KeyManager[], null, null) works
-- trustManagerFactory = TrustManagerFactory.getInstance(
-- TrustManagerFactory.getDefaultAlgorithm());
-- trustManagerFactory.init((KeyStore) null);
-- }
+- // Flush any data that may be implicitly generated by OpenSSL (handshake, close, etc..).
+- SSLEngineResult.HandshakeStatus status = NOT_HANDSHAKING;
+- // Prepare OpenSSL to work in server mode and receive handshake
+- if (handshakeState != HandshakeState.FINISHED) {
+- if (handshakeState != HandshakeState.STARTED_EXPLICITLY) {
+- // Update accepted so we know we triggered the handshake via wrap
+- handshakeState = HandshakeState.STARTED_IMPLICITLY;
+- }
+-
+- // Flush any data that may have been written implicitly during the handshake by OpenSSL.
+- bytesProduced = SSL.bioFlushByteBuffer(networkBIO);
+-
+- if (pendingException != null) {
+- // TODO(scott): It is possible that when the handshake failed there was not enough room in the
+- // non-application buffers to hold the alert. We should get all the data before progressing on.
+- // However I'm not aware of a way to do this with the OpenSSL APIs.
+- // See https://github.com/netty/netty/issues/6385.
+-
+- // We produced / consumed some data during the handshake, signal back to the caller.
+- // If there is a handshake exception and we have produced data, we should send the data before
+- // we allow handshake() to throw the handshake exception.
+- //
+- // When the user calls wrap() again we will propagate the handshake error back to the user as
+- // soon as there is no more data to was produced (as part of an alert etc).
+- if (bytesProduced > 0) {
+- return newResult(NEED_WRAP, 0, bytesProduced);
+- }
+- // Nothing was produced see if there is a handshakeException that needs to be propagated
+- // to the caller by calling handshakeException() which will return the right HandshakeStatus
+- // if it can "recover" from the exception for now.
+- return newResult(handshakeException(), 0, 0);
+- }
+-
+- status = handshake();
+-
+- // Handshake may have generated more data, for example if the internal SSL buffer is small
+- // we may have freed up space by flushing above.
+- bytesProduced = bioLengthBefore - SSL.bioLengthByteBuffer(networkBIO);
+-
+- if (status == NEED_TASK) {
+- return newResult(status, 0, bytesProduced);
+- }
+-
+- if (bytesProduced > 0) {
+- // If we have filled up the dst buffer and we have not finished the handshake we should try to
+- // wrap again. Otherwise we should only try to wrap again if there is still data pending in
+- // SSL buffers.
+- return newResult(mayFinishHandshake(status != FINISHED ?
+- bytesProduced == bioLengthBefore ? NEED_WRAP :
+- getHandshakeStatus(SSL.bioLengthNonApplication(networkBIO)) : FINISHED),
+- 0, bytesProduced);
+- }
+-
+- if (status == NEED_UNWRAP) {
+- // Signal if the outbound is done or not.
+- return isOutboundDone() ? NEED_UNWRAP_CLOSED : NEED_UNWRAP_OK;
+- }
-
-- final X509TrustManager manager = chooseTrustManager(trustManagerFactory.getTrustManagers());
+- // Explicit use outboundClosed and not outboundClosed() as we want to drain any bytes that are
+- // still present.
+- if (outboundClosed) {
+- bytesProduced = SSL.bioFlushByteBuffer(networkBIO);
+- return newResultMayFinishHandshake(status, 0, bytesProduced);
+- }
+- }
-
-- // IMPORTANT: The callbacks set for verification must be static to prevent memory leak as
-- // otherwise the context can never be collected. This is because the JNI code holds
-- // a global reference to the callbacks.
-- //
-- // See https://github.com/netty/netty/issues/5372
+- final int endOffset = offset + length;
+- if (jdkCompatibilityMode) {
+- int srcsLen = 0;
+- for (int i = offset; i < endOffset; ++i) {
+- final ByteBuffer src = srcs[i];
+- if (src == null) {
+- throw new IllegalArgumentException("srcs[" + i + "] is null");
+- }
+- if (srcsLen == MAX_PLAINTEXT_LENGTH) {
+- continue;
+- }
-
-- // Use this to prevent an error when running on java < 7
-- if (useExtendedTrustManager(manager)) {
-- SSLContext.setCertVerifyCallback(ctx,
-- new ExtendedTrustManagerVerifyCallback(engineMap, (X509ExtendedTrustManager) manager));
-- } else {
-- SSLContext.setCertVerifyCallback(ctx, new TrustManagerVerifyCallback(engineMap, manager));
-- }
+- srcsLen += src.remaining();
+- if (srcsLen > MAX_PLAINTEXT_LENGTH || srcsLen < 0) {
+- // If srcLen > MAX_PLAINTEXT_LENGTH or secLen < 0 just set it to MAX_PLAINTEXT_LENGTH.
+- // This also help us to guard against overflow.
+- // We not break out here as we still need to check for null entries in srcs[].
+- srcsLen = MAX_PLAINTEXT_LENGTH;
+- }
+- }
-
-- X509Certificate[] issuers = manager.getAcceptedIssuers();
-- if (issuers != null && issuers.length > 0) {
-- long bio = 0;
-- try {
-- bio = toBIO(issuers);
-- if (!SSLContext.setCACertificateBio(ctx, bio)) {
-- throw new SSLException("unable to setup accepted issuers for trustmanager " + manager);
+- // jdkCompatibilityMode will only produce a single TLS packet, and we don't aggregate src buffers,
+- // so we always fix the number of buffers to 1 when checking if the dst buffer is large enough.
+- if (!isBytesAvailableEnoughForWrap(dst.remaining(), srcsLen, 1)) {
+- return new SSLEngineResult(BUFFER_OVERFLOW, getHandshakeStatus(), 0, 0);
- }
-- } finally {
-- freeBio(bio);
- }
-- }
-
-- if (PlatformDependent.javaVersion() >= 8) {
-- // Only do on Java8+ as SNIMatcher is not supported in earlier releases.
-- // IMPORTANT: The callbacks set for hostname matching must be static to prevent memory leak as
-- // otherwise the context can never be collected. This is because the JNI code holds
-- // a global reference to the matcher.
-- SSLContext.setSniHostnameMatcher(ctx, new OpenSslSniHostnameMatcher(engineMap));
-- }
-- } catch (SSLException e) {
-- throw e;
-- } catch (Exception e) {
-- throw new SSLException("unable to setup trustmanager", e);
-- }
+- // There was no pending data in the network BIO -- encrypt any application data
+- int bytesConsumed = 0;
+- assert bytesProduced == 0;
-
-- result.sessionContext = new OpenSslServerSessionContext(thiz);
-- result.sessionContext.setSessionIdContext(ID);
-- return result;
-- }
+- // Flush any data that may have been written implicitly by OpenSSL in case a shutdown/alert occurs.
+- bytesProduced = SSL.bioFlushByteBuffer(networkBIO);
-
-- private static final class TrustManagerVerifyCallback extends AbstractCertificateVerifier {
-- private final X509TrustManager manager;
+- if (bytesProduced > 0) {
+- return newResultMayFinishHandshake(status, bytesConsumed, bytesProduced);
+- }
+- // There was a pending exception that we just delayed because there was something to produce left.
+- // Throw it now and shutdown the engine.
+- if (pendingException != null) {
+- Throwable error = pendingException;
+- pendingException = null;
+- shutdown();
+- // Throw a new exception wrapping the pending exception, so the stacktrace is meaningful and
+- // contains all the details.
+- throw new SSLException(error);
+- }
-
-- TrustManagerVerifyCallback(OpenSslEngineMap engineMap, X509TrustManager manager) {
-- super(engineMap);
-- this.manager = manager;
-- }
+- for (; offset < endOffset; ++offset) {
+- final ByteBuffer src = srcs[offset];
+- final int remaining = src.remaining();
+- if (remaining == 0) {
+- continue;
+- }
-
-- @Override
-- void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts, String auth)
-- throws Exception {
-- manager.checkClientTrusted(peerCerts, auth);
-- }
-- }
+- final int bytesWritten;
+- if (jdkCompatibilityMode) {
+- // Write plaintext application data to the SSL engine. We don't have to worry about checking
+- // if there is enough space if jdkCompatibilityMode because we only wrap at most
+- // MAX_PLAINTEXT_LENGTH and we loop over the input before hand and check if there is space.
+- bytesWritten = writePlaintextData(src, min(remaining, MAX_PLAINTEXT_LENGTH - bytesConsumed));
+- } else {
+- // OpenSSL's SSL_write keeps state between calls. We should make sure the amount we attempt to
+- // write is guaranteed to succeed so we don't have to worry about keeping state consistent
+- // between calls.
+- final int availableCapacityForWrap = dst.remaining() - bytesProduced - maxWrapOverhead;
+- if (availableCapacityForWrap <= 0) {
+- return new SSLEngineResult(BUFFER_OVERFLOW, getHandshakeStatus(), bytesConsumed,
+- bytesProduced);
+- }
+- bytesWritten = writePlaintextData(src, min(remaining, availableCapacityForWrap));
+- }
-
-- private static final class ExtendedTrustManagerVerifyCallback extends AbstractCertificateVerifier {
-- private final X509ExtendedTrustManager manager;
+- // Determine how much encrypted data was generated.
+- //
+- // Even if SSL_write doesn't consume any application data it is possible that OpenSSL will
+- // produce non-application data into the BIO. For example session tickets....
+- // See https://github.com/netty/netty/issues/10041
+- final int pendingNow = SSL.bioLengthByteBuffer(networkBIO);
+- bytesProduced += bioLengthBefore - pendingNow;
+- bioLengthBefore = pendingNow;
-
-- ExtendedTrustManagerVerifyCallback(OpenSslEngineMap engineMap, X509ExtendedTrustManager manager) {
-- super(engineMap);
-- this.manager = manager;
-- }
+- if (bytesWritten > 0) {
+- bytesConsumed += bytesWritten;
-
-- @Override
-- void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts, String auth)
-- throws Exception {
-- manager.checkClientTrusted(peerCerts, auth, engine);
-- }
-- }
+- if (jdkCompatibilityMode || bytesProduced == dst.remaining()) {
+- return newResultMayFinishHandshake(status, bytesConsumed, bytesProduced);
+- }
+- } else {
+- int sslError = SSL.getError(ssl, bytesWritten);
+- if (sslError == SSL.SSL_ERROR_ZERO_RETURN) {
+- // This means the connection was shutdown correctly, close inbound and outbound
+- if (!receivedShutdown) {
+- closeAll();
-
-- private static final class OpenSslSniHostnameMatcher implements SniHostNameMatcher {
-- private final OpenSslEngineMap engineMap;
+- bytesProduced += bioLengthBefore - SSL.bioLengthByteBuffer(networkBIO);
-
-- OpenSslSniHostnameMatcher(OpenSslEngineMap engineMap) {
-- this.engineMap = engineMap;
-- }
+- // If we have filled up the dst buffer and we have not finished the handshake we should
+- // try to wrap again. Otherwise we should only try to wrap again if there is still data
+- // pending in SSL buffers.
+- SSLEngineResult.HandshakeStatus hs = mayFinishHandshake(
+- status != FINISHED ? bytesProduced == dst.remaining() ? NEED_WRAP
+- : getHandshakeStatus(SSL.bioLengthNonApplication(networkBIO))
+- : FINISHED);
+- return newResult(hs, bytesConsumed, bytesProduced);
+- }
-
-- @Override
-- public boolean match(long ssl, String hostname) {
-- ReferenceCountedOpenSslEngine engine = engineMap.get(ssl);
-- if (engine != null) {
-- return engine.checkSniHostnameMatch(hostname);
-- }
-- logger.warn("No ReferenceCountedOpenSslEngine found for SSL pointer: {}", ssl);
-- return false;
-- }
-- }
--}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/SslContext.java b/handler/src/main/java/io/netty/handler/ssl/SslContext.java
-index 4998d0d..8dbc3cf 100644
---- a/handler/src/main/java/io/netty/handler/ssl/SslContext.java
-+++ b/handler/src/main/java/io/netty/handler/ssl/SslContext.java
-@@ -115,11 +115,7 @@ public abstract class SslContext {
- }
-
- private static SslProvider defaultProvider() {
-- if (OpenSsl.isAvailable()) {
-- return SslProvider.OPENSSL;
-- } else {
-- return SslProvider.JDK;
-- }
-+ return SslProvider.JDK;
- }
-
- /**
-@@ -416,18 +412,6 @@ public abstract class SslContext {
- trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword,
- keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout,
- clientAuth, protocols, startTls);
-- case OPENSSL:
-- verifyNullSslContextProvider(provider, sslContextProvider);
-- return new OpenSslServerContext(
-- trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword,
-- keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout,
-- clientAuth, protocols, startTls, enableOcsp);
-- case OPENSSL_REFCNT:
-- verifyNullSslContextProvider(provider, sslContextProvider);
-- return new ReferenceCountedOpenSslServerContext(
-- trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword,
-- keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout,
-- clientAuth, protocols, startTls, enableOcsp);
- default:
- throw new Error(provider.toString());
- }
-@@ -770,18 +754,6 @@ public abstract class SslContext {
- return new JdkSslClientContext(sslContextProvider,
- trustCert, trustManagerFactory, keyCertChain, key, keyPassword,
- keyManagerFactory, ciphers, cipherFilter, apn, protocols, sessionCacheSize, sessionTimeout);
-- case OPENSSL:
-- verifyNullSslContextProvider(provider, sslContextProvider);
-- return new OpenSslClientContext(
-- trustCert, trustManagerFactory, keyCertChain, key, keyPassword,
-- keyManagerFactory, ciphers, cipherFilter, apn, protocols, sessionCacheSize, sessionTimeout,
-- enableOcsp);
-- case OPENSSL_REFCNT:
-- verifyNullSslContextProvider(provider, sslContextProvider);
-- return new ReferenceCountedOpenSslClientContext(
-- trustCert, trustManagerFactory, keyCertChain, key, keyPassword,
-- keyManagerFactory, ciphers, cipherFilter, apn, protocols, sessionCacheSize, sessionTimeout,
-- enableOcsp);
- default:
- throw new Error(provider.toString());
- }
-diff --git a/handler/src/main/java/io/netty/handler/ssl/SslHandler.java b/handler/src/main/java/io/netty/handler/ssl/SslHandler.java
-index c054964..05c451a 100644
---- a/handler/src/main/java/io/netty/handler/ssl/SslHandler.java
-+++ b/handler/src/main/java/io/netty/handler/ssl/SslHandler.java
-@@ -159,6 +159,12 @@ import static io.netty.handler.ssl.SslUtils.getEncryptedPacketLength;
- * <a href="https://github.com/netty/netty/issues/832">#832</a> in our issue tracker.
- */
- public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundHandler {
-+ private static final int MAX_PLAINTEXT_LENGTH = 16 * 1024; // 2^14
-+ private static final int MAX_COMPRESSED_LENGTH = MAX_PLAINTEXT_LENGTH + 1024;
-+ private static final int MAX_CIPHERTEXT_LENGTH = MAX_COMPRESSED_LENGTH + 1024;
-+ // Header (5) + Data (2^14) + Compression (1024) + Encryption (1024) + MAC (20) + Padding (256)
-+ static final int MAX_ENCRYPTED_PACKET_LENGTH = MAX_CIPHERTEXT_LENGTH + 5 + 20 + 256;
-+ static final int MAX_ENCRYPTION_OVERHEAD_LENGTH = MAX_ENCRYPTED_PACKET_LENGTH - MAX_PLAINTEXT_LENGTH;
-
- private static final InternalLogger logger =
- InternalLoggerFactory.getInstance(SslHandler.class);
-@@ -181,40 +187,6 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
- new ClosedChannelException(), SslHandler.class, "channelInactive(...)");
-
- private enum SslEngineType {
-- TCNATIVE(true, COMPOSITE_CUMULATOR) {
-- @Override
-- SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int len, ByteBuf out)
-- throws SSLException {
-- int nioBufferCount = in.nioBufferCount();
-- int writerIndex = out.writerIndex();
-- final SSLEngineResult result;
-- if (nioBufferCount > 1) {
-- /*
-- * If {@link OpenSslEngine} is in use,
-- * we can use a special {@link OpenSslEngine#unwrap(ByteBuffer[], ByteBuffer[])} method
-- * that accepts multiple {@link ByteBuffer}s without additional memory copies.
-- */
-- ReferenceCountedOpenSslEngine opensslEngine = (ReferenceCountedOpenSslEngine) handler.engine;
-- try {
-- handler.singleBuffer[0] = toByteBuffer(out, writerIndex,
-- out.writableBytes());
-- result = opensslEngine.unwrap(in.nioBuffers(readerIndex, len), handler.singleBuffer);
-- } finally {
-- handler.singleBuffer[0] = null;
+- return newResult(NOT_HANDSHAKING, bytesConsumed, bytesProduced);
+- } else if (sslError == SSL.SSL_ERROR_WANT_READ) {
+- // If there is no pending data to read from BIO we should go back to event loop and try
+- // to read more data [1]. It is also possible that event loop will detect the socket has
+- // been closed. [1] https://www.openssl.org/docs/manmaster/ssl/SSL_write.html
+- return newResult(NEED_UNWRAP, bytesConsumed, bytesProduced);
+- } else if (sslError == SSL.SSL_ERROR_WANT_WRITE) {
+- // SSL_ERROR_WANT_WRITE typically means that the underlying transport is not writable
+- // and we should set the "want write" flag on the selector and try again when the
+- // underlying transport is writable [1]. However we are not directly writing to the
+- // underlying transport and instead writing to a BIO buffer. The OpenSsl documentation
+- // says we should do the following [1]:
+- //
+- // "When using a buffering BIO, like a BIO pair, data must be written into or retrieved
+- // out of the BIO before being able to continue."
+- //
+- // In practice this means the destination buffer doesn't have enough space for OpenSSL
+- // to write encrypted data to. This is an OVERFLOW condition.
+- // [1] https://www.openssl.org/docs/manmaster/ssl/SSL_write.html
+- if (bytesProduced > 0) {
+- // If we produced something we should report this back and let the user call
+- // wrap again.
+- return newResult(NEED_WRAP, bytesConsumed, bytesProduced);
+- }
+- return newResult(BUFFER_OVERFLOW, status, bytesConsumed, bytesProduced);
+- } else if (sslError == SSL.SSL_ERROR_WANT_X509_LOOKUP ||
+- sslError == SSL.SSL_ERROR_WANT_CERTIFICATE_VERIFY ||
+- sslError == SSL.SSL_ERROR_WANT_PRIVATE_KEY_OPERATION) {
+-
+- return newResult(NEED_TASK, bytesConsumed, bytesProduced);
+- } else {
+- // Everything else is considered as error
+- throw shutdownWithError("SSL_write", sslError);
+- }
- }
-- } else {
-- result = handler.engine.unwrap(toByteBuffer(in, readerIndex, len),
-- toByteBuffer(out, writerIndex, out.writableBytes()));
- }
-- out.writerIndex(writerIndex + result.bytesProduced());
-- return result;
-- }
--
-- @Override
-- int calculateWrapBufferCapacity(SslHandler handler, int pendingBytes, int numComponents) {
-- return ReferenceCountedOpenSslEngine.calculateOutNetBufSize(pendingBytes, numComponents);
-- }
-- },
- CONSCRYPT(true, COMPOSITE_CUMULATOR) {
- @Override
- SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int len, ByteBuf out)
-@@ -265,9 +237,6 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
- };
-
- static SslEngineType forEngine(SSLEngine engine) {
-- if (engine instanceof ReferenceCountedOpenSslEngine) {
-- return TCNATIVE;
-- }
- if (engine instanceof ConscryptAlpnSslEngine) {
- return CONSCRYPT;
- }
-@@ -1034,7 +1003,7 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
-
- boolean nonSslRecord = false;
-
-- while (totalLength < ReferenceCountedOpenSslEngine.MAX_ENCRYPTED_PACKET_LENGTH) {
-+ while (totalLength < MAX_ENCRYPTED_PACKET_LENGTH) {
- final int readableBytes = endOffset - offset;
- if (readableBytes < SslUtils.SSL_RECORD_HEADER_LENGTH) {
- break;
-@@ -1055,7 +1024,7 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
- }
-
- int newTotalLength = totalLength + packetLength;
-- if (newTotalLength > ReferenceCountedOpenSslEngine.MAX_ENCRYPTED_PACKET_LENGTH) {
-+ if (newTotalLength > MAX_ENCRYPTED_PACKET_LENGTH) {
- // Don't read too much.
- break;
- }
-diff --git a/handler/src/main/java/io/netty/handler/ssl/ocsp/OcspClientHandler.java b/handler/src/main/java/io/netty/handler/ssl/ocsp/OcspClientHandler.java
-deleted file mode 100644
-index aff0949..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/ocsp/OcspClientHandler.java
-+++ /dev/null
-@@ -1,65 +0,0 @@
--/*
-- * Copyright 2017 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl.ocsp;
--
--import io.netty.channel.ChannelHandlerContext;
--import io.netty.channel.ChannelInboundHandlerAdapter;
--import io.netty.handler.ssl.ReferenceCountedOpenSslContext;
--import io.netty.handler.ssl.ReferenceCountedOpenSslEngine;
--import io.netty.handler.ssl.SslHandshakeCompletionEvent;
--import io.netty.util.internal.ObjectUtil;
--import io.netty.util.internal.ThrowableUtil;
--import io.netty.util.internal.UnstableApi;
+- return newResultMayFinishHandshake(status, bytesConsumed, bytesProduced);
+- } finally {
+- SSL.bioClearByteBuffer(networkBIO);
+- if (bioReadCopyBuf == null) {
+- dst.position(dst.position() + bytesProduced);
+- } else {
+- assert bioReadCopyBuf.readableBytes() <= dst.remaining() : "The destination buffer " + dst +
+- " didn't have enough remaining space to hold the encrypted content in " + bioReadCopyBuf;
+- dst.put(bioReadCopyBuf.internalNioBuffer(bioReadCopyBuf.readerIndex(), bytesProduced));
+- bioReadCopyBuf.release();
+- }
+- }
+- }
+- }
-
--import javax.net.ssl.SSLHandshakeException;
+- private SSLEngineResult newResult(SSLEngineResult.HandshakeStatus hs, int bytesConsumed, int bytesProduced) {
+- return newResult(OK, hs, bytesConsumed, bytesProduced);
+- }
-
--/**
-- * A handler for SSL clients to handle and act upon stapled OCSP responses.
-- *
-- * @see ReferenceCountedOpenSslContext#enableOcsp()
-- * @see ReferenceCountedOpenSslEngine#getOcspResponse()
-- */
--@UnstableApi
--public abstract class OcspClientHandler extends ChannelInboundHandlerAdapter {
+- private SSLEngineResult newResult(SSLEngineResult.Status status, SSLEngineResult.HandshakeStatus hs,
+- int bytesConsumed, int bytesProduced) {
+- // If isOutboundDone, then the data from the network BIO
+- // was the close_notify message and all was consumed we are not required to wait
+- // for the receipt the peer's close_notify message -- shutdown.
+- if (isOutboundDone()) {
+- if (isInboundDone()) {
+- // If the inbound was done as well, we need to ensure we return NOT_HANDSHAKING to signal we are done.
+- hs = NOT_HANDSHAKING;
-
-- private static final SSLHandshakeException OCSP_VERIFICATION_EXCEPTION = ThrowableUtil.unknownStackTrace(
-- new SSLHandshakeException("Bad OCSP response"), OcspClientHandler.class, "verify(...)");
+- // As the inbound and the outbound is done we can shutdown the engine now.
+- shutdown();
+- }
+- return new SSLEngineResult(CLOSED, hs, bytesConsumed, bytesProduced);
+- }
+- if (hs == NEED_TASK) {
+- // Set needTask to true so getHandshakeStatus() will return the correct value.
+- needTask = true;
+- }
+- return new SSLEngineResult(status, hs, bytesConsumed, bytesProduced);
+- }
-
-- private final ReferenceCountedOpenSslEngine engine;
+- private SSLEngineResult newResultMayFinishHandshake(SSLEngineResult.HandshakeStatus hs,
+- int bytesConsumed, int bytesProduced) throws SSLException {
+- return newResult(mayFinishHandshake(hs != FINISHED ? getHandshakeStatus() : FINISHED),
+- bytesConsumed, bytesProduced);
+- }
-
-- protected OcspClientHandler(ReferenceCountedOpenSslEngine engine) {
-- this.engine = ObjectUtil.checkNotNull(engine, "engine");
+- private SSLEngineResult newResultMayFinishHandshake(SSLEngineResult.Status status,
+- SSLEngineResult.HandshakeStatus hs,
+- int bytesConsumed, int bytesProduced) throws SSLException {
+- return newResult(status, mayFinishHandshake(hs != FINISHED ? getHandshakeStatus() : FINISHED),
+- bytesConsumed, bytesProduced);
- }
-
- /**
-- * @see ReferenceCountedOpenSslEngine#getOcspResponse()
+- * Log the error, shutdown the engine and throw an exception.
- */
-- protected abstract boolean verify(ChannelHandlerContext ctx, ReferenceCountedOpenSslEngine engine) throws Exception;
+- private SSLException shutdownWithError(String operations, int sslError) {
+- return shutdownWithError(operations, sslError, SSL.getLastErrorNumber());
+- }
-
-- @Override
-- public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
-- if (evt instanceof SslHandshakeCompletionEvent) {
-- ctx.pipeline().remove(this);
+- private SSLException shutdownWithError(String operation, int sslError, int error) {
+- String errorString = SSL.getErrorString(error);
+- if (logger.isDebugEnabled()) {
+- logger.debug("{} failed with {}: OpenSSL error: {} {}",
+- operation, sslError, error, errorString);
+- }
-
-- SslHandshakeCompletionEvent event = (SslHandshakeCompletionEvent) evt;
-- if (event.isSuccess() && !verify(ctx, engine)) {
-- throw OCSP_VERIFICATION_EXCEPTION;
-- }
+- // There was an internal error -- shutdown
+- shutdown();
+- if (handshakeState == HandshakeState.FINISHED) {
+- return new SSLException(errorString);
- }
-
-- ctx.fireUserEventTriggered(evt);
+- SSLHandshakeException exception = new SSLHandshakeException(errorString);
+- // If we have a handshakeException stored already we should include it as well to help the user debug things.
+- if (pendingException != null) {
+- exception.initCause(pendingException);
+- pendingException = null;
+- }
+- return exception;
- }
--}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/ocsp/package-info.java b/handler/src/main/java/io/netty/handler/ssl/ocsp/package-info.java
-deleted file mode 100644
-index 2883ff4..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/ocsp/package-info.java
-+++ /dev/null
-@@ -1,23 +0,0 @@
--/*
-- * Copyright 2017 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
-
--/**
-- * <a href="https://en.wikipedia.org/wiki/OCSP_stapling">OCSP stapling</a>,
-- * formally known as the TLS Certificate Status Request extension, is an
-- * alternative approach to the Online Certificate Status Protocol (OCSP)
-- * for checking the revocation status of X.509 digital certificates.
-- */
--package io.netty.handler.ssl.ocsp;
-diff --git a/handler/src/test/java/io/netty/handler/ssl/JdkOpenSslEngineInteroptTest.java b/handler/src/test/java/io/netty/handler/ssl/JdkOpenSslEngineInteroptTest.java
-deleted file mode 100644
-index d696d6b..0000000
---- a/handler/src/test/java/io/netty/handler/ssl/JdkOpenSslEngineInteroptTest.java
-+++ /dev/null
-@@ -1,108 +0,0 @@
--/*
-- * Copyright 2016 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
+- public final SSLEngineResult unwrap(
+- final ByteBuffer[] srcs, int srcsOffset, final int srcsLength,
+- final ByteBuffer[] dsts, int dstsOffset, final int dstsLength) throws SSLException {
+-
+- // Throw required runtime exceptions
+- ObjectUtil.checkNotNull(srcs, "srcs");
+- if (srcsOffset >= srcs.length
+- || srcsOffset + srcsLength > srcs.length) {
+- throw new IndexOutOfBoundsException(
+- "offset: " + srcsOffset + ", length: " + srcsLength +
+- " (expected: offset <= offset + length <= srcs.length (" + srcs.length + "))");
+- }
+- if (dsts == null) {
+- throw new IllegalArgumentException("dsts is null");
+- }
+- if (dstsOffset >= dsts.length || dstsOffset + dstsLength > dsts.length) {
+- throw new IndexOutOfBoundsException(
+- "offset: " + dstsOffset + ", length: " + dstsLength +
+- " (expected: offset <= offset + length <= dsts.length (" + dsts.length + "))");
+- }
+- long capacity = 0;
+- final int dstsEndOffset = dstsOffset + dstsLength;
+- for (int i = dstsOffset; i < dstsEndOffset; i ++) {
+- ByteBuffer dst = dsts[i];
+- if (dst == null) {
+- throw new IllegalArgumentException("dsts[" + i + "] is null");
+- }
+- if (dst.isReadOnly()) {
+- throw new ReadOnlyBufferException();
+- }
+- capacity += dst.remaining();
+- }
-
--import org.junit.BeforeClass;
--import org.junit.Test;
--import org.junit.runner.RunWith;
--import org.junit.runners.Parameterized;
+- final int srcsEndOffset = srcsOffset + srcsLength;
+- long len = 0;
+- for (int i = srcsOffset; i < srcsEndOffset; i++) {
+- ByteBuffer src = srcs[i];
+- if (src == null) {
+- throw new IllegalArgumentException("srcs[" + i + "] is null");
+- }
+- len += src.remaining();
+- }
-
--import java.util.ArrayList;
--import java.util.Collection;
--import java.util.List;
+- synchronized (this) {
+- if (isInboundDone()) {
+- return isOutboundDone() || isDestroyed() ? CLOSED_NOT_HANDSHAKING : NEED_WRAP_CLOSED;
+- }
+-
+- SSLEngineResult.HandshakeStatus status = NOT_HANDSHAKING;
+- // Prepare OpenSSL to work in server mode and receive handshake
+- if (handshakeState != HandshakeState.FINISHED) {
+- if (handshakeState != HandshakeState.STARTED_EXPLICITLY) {
+- // Update accepted so we know we triggered the handshake via wrap
+- handshakeState = HandshakeState.STARTED_IMPLICITLY;
+- }
+-
+- status = handshake();
+-
+- if (status == NEED_TASK) {
+- return newResult(status, 0, 0);
+- }
+-
+- if (status == NEED_WRAP) {
+- return NEED_WRAP_OK;
+- }
+- // Check if the inbound is considered to be closed if so let us try to wrap again.
+- if (isInboundDone) {
+- return NEED_WRAP_CLOSED;
+- }
+- }
+-
+- int sslPending = sslPending0();
+- int packetLength;
+- // The JDK implies that only a single SSL packet should be processed per unwrap call [1]. If we are in
+- // JDK compatibility mode then we should honor this, but if not we just wrap as much as possible. If there
+- // are multiple records or partial records this may reduce thrashing events through the pipeline.
+- // [1] https://docs.oracle.com/javase/7/docs/api/javax/net/ssl/SSLEngine.html
+- if (jdkCompatibilityMode) {
+- if (len < SSL_RECORD_HEADER_LENGTH) {
+- return newResultMayFinishHandshake(BUFFER_UNDERFLOW, status, 0, 0);
+- }
+-
+- packetLength = SslUtils.getEncryptedPacketLength(srcs, srcsOffset);
+- if (packetLength == SslUtils.NOT_ENCRYPTED) {
+- throw new NotSslRecordException("not an SSL/TLS record");
+- }
+-
+- final int packetLengthDataOnly = packetLength - SSL_RECORD_HEADER_LENGTH;
+- if (packetLengthDataOnly > capacity) {
+- // Not enough space in the destination buffer so signal the caller that the buffer needs to be
+- // increased.
+- if (packetLengthDataOnly > MAX_RECORD_SIZE) {
+- // The packet length MUST NOT exceed 2^14 [1]. However we do accommodate more data to support
+- // legacy use cases which may violate this condition (e.g. OpenJDK's SslEngineImpl). If the max
+- // length is exceeded we fail fast here to avoid an infinite loop due to the fact that we
+- // won't allocate a buffer large enough.
+- // [1] https://tools.ietf.org/html/rfc5246#section-6.2.1
+- throw new SSLException("Illegal packet length: " + packetLengthDataOnly + " > " +
+- session.getApplicationBufferSize());
+- } else {
+- session.tryExpandApplicationBufferSize(packetLengthDataOnly);
+- }
+- return newResultMayFinishHandshake(BUFFER_OVERFLOW, status, 0, 0);
+- }
+-
+- if (len < packetLength) {
+- // We either don't have enough data to read the packet length or not enough for reading the whole
+- // packet.
+- return newResultMayFinishHandshake(BUFFER_UNDERFLOW, status, 0, 0);
+- }
+- } else if (len == 0 && sslPending <= 0) {
+- return newResultMayFinishHandshake(BUFFER_UNDERFLOW, status, 0, 0);
+- } else if (capacity == 0) {
+- return newResultMayFinishHandshake(BUFFER_OVERFLOW, status, 0, 0);
+- } else {
+- packetLength = (int) min(MAX_VALUE, len);
+- }
+-
+- // This must always be the case when we reached here as if not we returned BUFFER_UNDERFLOW.
+- assert srcsOffset < srcsEndOffset;
+-
+- // This must always be the case if we reached here.
+- assert capacity > 0;
+-
+- // Number of produced bytes
+- int bytesProduced = 0;
+- int bytesConsumed = 0;
+- try {
+- srcLoop:
+- for (;;) {
+- ByteBuffer src = srcs[srcsOffset];
+- int remaining = src.remaining();
+- final ByteBuf bioWriteCopyBuf;
+- int pendingEncryptedBytes;
+- if (remaining == 0) {
+- if (sslPending <= 0) {
+- // We must skip empty buffers as BIO_write will return 0 if asked to write something
+- // with length 0.
+- if (++srcsOffset >= srcsEndOffset) {
+- break;
+- }
+- continue;
+- } else {
+- bioWriteCopyBuf = null;
+- pendingEncryptedBytes = SSL.bioLengthByteBuffer(networkBIO);
+- }
+- } else {
+- // Write more encrypted data into the BIO. Ensure we only read one packet at a time as
+- // stated in the SSLEngine javadocs.
+- pendingEncryptedBytes = min(packetLength, remaining);
+- bioWriteCopyBuf = writeEncryptedData(src, pendingEncryptedBytes);
+- }
+- try {
+- for (;;) {
+- ByteBuffer dst = dsts[dstsOffset];
+- if (!dst.hasRemaining()) {
+- // No space left in the destination buffer, skip it.
+- if (++dstsOffset >= dstsEndOffset) {
+- break srcLoop;
+- }
+- continue;
+- }
+-
+- int bytesRead = readPlaintextData(dst);
+- // We are directly using the ByteBuffer memory for the write, and so we only know what has
+- // been consumed after we let SSL decrypt the data. At this point we should update the
+- // number of bytes consumed, update the ByteBuffer position, and release temp ByteBuf.
+- int localBytesConsumed = pendingEncryptedBytes - SSL.bioLengthByteBuffer(networkBIO);
+- bytesConsumed += localBytesConsumed;
+- packetLength -= localBytesConsumed;
+- pendingEncryptedBytes -= localBytesConsumed;
+- src.position(src.position() + localBytesConsumed);
+-
+- if (bytesRead > 0) {
+- bytesProduced += bytesRead;
+-
+- if (!dst.hasRemaining()) {
+- sslPending = sslPending0();
+- // Move to the next dst buffer as this one is full.
+- if (++dstsOffset >= dstsEndOffset) {
+- return sslPending > 0 ?
+- newResult(BUFFER_OVERFLOW, status, bytesConsumed, bytesProduced) :
+- newResultMayFinishHandshake(isInboundDone() ? CLOSED : OK, status,
+- bytesConsumed, bytesProduced);
+- }
+- } else if (packetLength == 0 || jdkCompatibilityMode) {
+- // We either consumed all data or we are in jdkCompatibilityMode and have consumed
+- // a single TLS packet and should stop consuming until this method is called again.
+- break srcLoop;
+- }
+- } else {
+- int sslError = SSL.getError(ssl, bytesRead);
+- if (sslError == SSL.SSL_ERROR_WANT_READ || sslError == SSL.SSL_ERROR_WANT_WRITE) {
+- // break to the outer loop as we want to read more data which means we need to
+- // write more to the BIO.
+- break;
+- } else if (sslError == SSL.SSL_ERROR_ZERO_RETURN) {
+- // This means the connection was shutdown correctly, close inbound and outbound
+- if (!receivedShutdown) {
+- closeAll();
+- }
+- return newResultMayFinishHandshake(isInboundDone() ? CLOSED : OK, status,
+- bytesConsumed, bytesProduced);
+- } else if (sslError == SSL.SSL_ERROR_WANT_X509_LOOKUP ||
+- sslError == SSL.SSL_ERROR_WANT_CERTIFICATE_VERIFY ||
+- sslError == SSL.SSL_ERROR_WANT_PRIVATE_KEY_OPERATION) {
+- return newResult(isInboundDone() ? CLOSED : OK,
+- NEED_TASK, bytesConsumed, bytesProduced);
+- } else {
+- return sslReadErrorResult(sslError, SSL.getLastErrorNumber(), bytesConsumed,
+- bytesProduced);
+- }
+- }
+- }
-
--import static io.netty.handler.ssl.OpenSslTestUtils.checkShouldUseKeyManagerFactory;
--import static io.netty.internal.tcnative.SSL.SSL_CVERIFY_IGNORED;
--import static org.junit.Assume.assumeTrue;
+- if (++srcsOffset >= srcsEndOffset) {
+- break;
+- }
+- } finally {
+- if (bioWriteCopyBuf != null) {
+- bioWriteCopyBuf.release();
+- }
+- }
+- }
+- } finally {
+- SSL.bioClearByteBuffer(networkBIO);
+- rejectRemoteInitiatedRenegotiation();
+- }
-
--(a)RunWith(Parameterized.class)
--public class JdkOpenSslEngineInteroptTest extends SSLEngineTest {
+- // Check to see if we received a close_notify message from the peer.
+- if (!receivedShutdown && (SSL.getShutdown(ssl) & SSL.SSL_RECEIVED_SHUTDOWN) == SSL.SSL_RECEIVED_SHUTDOWN) {
+- closeAll();
+- }
-
-- @Parameterized.Parameters(name = "{index}: bufferType = {0}")
-- public static Collection<Object> data() {
-- List<Object> params = new ArrayList<Object>();
-- for (BufferType type: BufferType.values()) {
-- params.add(type);
+- return newResultMayFinishHandshake(isInboundDone() ? CLOSED : OK, status, bytesConsumed, bytesProduced);
- }
-- return params;
- }
-
-- public JdkOpenSslEngineInteroptTest(BufferType type) {
-- super(type);
+- private SSLEngineResult sslReadErrorResult(int error, int stackError, int bytesConsumed, int bytesProduced)
+- throws SSLException {
+- // Check if we have a pending handshakeException and if so see if we need to consume all pending data from the
+- // BIO first or can just shutdown and throw it now.
+- // This is needed so we ensure close_notify etc is correctly send to the remote peer.
+- // See https://github.com/netty/netty/issues/3900
+- if (SSL.bioLengthNonApplication(networkBIO) > 0) {
+- // we seems to have data left that needs to be transferred and so the user needs
+- // call wrap(...). Store the error so we can pick it up later.
+- String message = SSL.getErrorString(stackError);
+- SSLException exception = handshakeState == HandshakeState.FINISHED ?
+- new SSLException(message) : new SSLHandshakeException(message);
+- if (pendingException == null) {
+- pendingException = exception;
+- } else {
+- ThrowableUtil.addSuppressed(pendingException, exception);
+- }
+- // We need to clear all errors so we not pick up anything that was left on the stack on the next
+- // operation. Note that shutdownWithError(...) will cleanup the stack as well so its only needed here.
+- SSL.clearError();
+- return new SSLEngineResult(OK, NEED_WRAP, bytesConsumed, bytesProduced);
+- }
+- throw shutdownWithError("SSL_read", error, stackError);
- }
-
-- @BeforeClass
-- public static void checkOpenSsl() {
-- assumeTrue(OpenSsl.isAvailable());
+- private void closeAll() throws SSLException {
+- receivedShutdown = true;
+- closeOutbound();
+- closeInbound();
- }
-
-- @Override
-- protected SslProvider sslClientProvider() {
-- return SslProvider.JDK;
+- private void rejectRemoteInitiatedRenegotiation() throws SSLHandshakeException {
+- // As rejectRemoteInitiatedRenegotiation() is called in a finally block we also need to check if we shutdown
+- // the engine before as otherwise SSL.getHandshakeCount(ssl) will throw an NPE if the passed in ssl is 0.
+- // See https://github.com/netty/netty/issues/7353
+- if (!isDestroyed() && SSL.getHandshakeCount(ssl) > 1 &&
+- // As we may count multiple handshakes when TLSv1.3 is used we should just ignore this here as
+- // renegotiation is not supported in TLSv1.3 as per spec.
+- !SslUtils.PROTOCOL_TLS_V1_3.equals(session.getProtocol()) && handshakeState == HandshakeState.FINISHED) {
+- // TODO: In future versions me may also want to send a fatal_alert to the client and so notify it
+- // that the renegotiation failed.
+- shutdown();
+- throw new SSLHandshakeException("remote-initiated renegotiation not allowed");
+- }
- }
-
-- @Override
-- protected SslProvider sslServerProvider() {
-- return SslProvider.OPENSSL;
+- public final SSLEngineResult unwrap(final ByteBuffer[] srcs, final ByteBuffer[] dsts) throws SSLException {
+- return unwrap(srcs, 0, srcs.length, dsts, 0, dsts.length);
- }
-
-- @Override
-- @Test
-- public void testMutualAuthInvalidIntermediateCASucceedWithOptionalClientAuth() throws Exception {
-- checkShouldUseKeyManagerFactory();
-- super.testMutualAuthInvalidIntermediateCASucceedWithOptionalClientAuth();
+- private ByteBuffer[] singleSrcBuffer(ByteBuffer src) {
+- singleSrcBuffer[0] = src;
+- return singleSrcBuffer;
- }
-
-- @Override
-- @Test
-- public void testMutualAuthInvalidIntermediateCAFailWithOptionalClientAuth() throws Exception {
-- checkShouldUseKeyManagerFactory();
-- super.testMutualAuthInvalidIntermediateCAFailWithOptionalClientAuth();
+- private void resetSingleSrcBuffer() {
+- singleSrcBuffer[0] = null;
- }
-
-- @Override
-- @Test
-- public void testMutualAuthInvalidIntermediateCAFailWithRequiredClientAuth() throws Exception {
-- checkShouldUseKeyManagerFactory();
-- super.testMutualAuthInvalidIntermediateCAFailWithRequiredClientAuth();
+- private ByteBuffer[] singleDstBuffer(ByteBuffer src) {
+- singleDstBuffer[0] = src;
+- return singleDstBuffer;
- }
-
-- @Override
-- @Test
-- public void testMutualAuthValidClientCertChainTooLongFailOptionalClientAuth() throws Exception {
-- checkShouldUseKeyManagerFactory();
-- super.testMutualAuthValidClientCertChainTooLongFailOptionalClientAuth();
+- private void resetSingleDstBuffer() {
+- singleDstBuffer[0] = null;
- }
-
- @Override
-- @Test
-- public void testMutualAuthValidClientCertChainTooLongFailRequireClientAuth() throws Exception {
-- checkShouldUseKeyManagerFactory();
-- super.testMutualAuthValidClientCertChainTooLongFailRequireClientAuth();
+- public final synchronized SSLEngineResult unwrap(
+- final ByteBuffer src, final ByteBuffer[] dsts, final int offset, final int length) throws SSLException {
+- try {
+- return unwrap(singleSrcBuffer(src), 0, 1, dsts, offset, length);
+- } finally {
+- resetSingleSrcBuffer();
+- }
- }
-
- @Override
-- protected void mySetupMutualAuthServerInitSslHandler(SslHandler handler) {
-- ReferenceCountedOpenSslEngine engine = (ReferenceCountedOpenSslEngine) handler.engine();
-- engine.setVerify(SSL_CVERIFY_IGNORED, 1);
+- public final synchronized SSLEngineResult wrap(ByteBuffer src, ByteBuffer dst) throws SSLException {
+- try {
+- return wrap(singleSrcBuffer(src), dst);
+- } finally {
+- resetSingleSrcBuffer();
+- }
- }
-
- @Override
-- protected boolean mySetupMutualAuthServerIsValidClientException(Throwable cause) {
-- // TODO(scott): work around for a JDK issue. The exception should be SSLHandshakeException.
-- return super.mySetupMutualAuthServerIsValidClientException(cause) || causedBySSLException(cause);
-- }
--}
-diff --git a/handler/src/test/java/io/netty/handler/ssl/OpenSslCertificateExceptionTest.java b/handler/src/test/java/io/netty/handler/ssl/OpenSslCertificateExceptionTest.java
-deleted file mode 100644
-index 229e853..0000000
---- a/handler/src/test/java/io/netty/handler/ssl/OpenSslCertificateExceptionTest.java
-+++ /dev/null
-@@ -1,49 +0,0 @@
--/*
-- * Copyright 2017 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
--
--import io.netty.internal.tcnative.CertificateVerifier;
--import org.junit.Assert;
--import org.junit.Assume;
--import org.junit.BeforeClass;
--import org.junit.Test;
--
--import java.lang.reflect.Field;
--
--public class OpenSslCertificateExceptionTest {
--
-- @BeforeClass
-- public static void assumeOpenSsl() {
-- Assume.assumeTrue(OpenSsl.isAvailable());
-- }
--
-- @Test
-- public void testValidErrorCode() throws Exception {
-- Field[] fields = CertificateVerifier.class.getFields();
-- for (Field field : fields) {
-- if (field.isAccessible()) {
-- int errorCode = field.getInt(null);
-- OpenSslCertificateException exception = new OpenSslCertificateException(errorCode);
-- Assert.assertEquals(errorCode, exception.errorCode());
-- }
+- public final synchronized SSLEngineResult unwrap(ByteBuffer src, ByteBuffer dst) throws SSLException {
+- try {
+- return unwrap(singleSrcBuffer(src), singleDstBuffer(dst));
+- } finally {
+- resetSingleSrcBuffer();
+- resetSingleDstBuffer();
- }
- }
-
-- @Test(expected = IllegalArgumentException.class)
-- public void testNonValidErrorCode() {
-- new OpenSslCertificateException(Integer.MIN_VALUE);
-- }
--}
-diff --git a/handler/src/test/java/io/netty/handler/ssl/OpenSslClientContextTest.java b/handler/src/test/java/io/netty/handler/ssl/OpenSslClientContextTest.java
-deleted file mode 100644
-index 6011cf7..0000000
---- a/handler/src/test/java/io/netty/handler/ssl/OpenSslClientContextTest.java
-+++ /dev/null
-@@ -1,38 +0,0 @@
--/*
-- * Copyright 2016 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
--
--import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
--import org.junit.BeforeClass;
--
--import javax.net.ssl.SSLException;
--import java.io.File;
--
--import static org.junit.Assume.assumeTrue;
--
--public class OpenSslClientContextTest extends SslContextTest {
--
-- @BeforeClass
-- public static void checkOpenSsl() {
-- assumeTrue(OpenSsl.isAvailable());
-- }
--
- @Override
-- protected SslContext newServerContext(File crtFile, File keyFile, String pass) throws SSLException {
-- return new OpenSslClientContext(crtFile, InsecureTrustManagerFactory.INSTANCE, crtFile, keyFile, pass,
-- null, null, IdentityCipherSuiteFilter.INSTANCE, ApplicationProtocolConfig.DISABLED, 0, 0);
-- }
--}
-diff --git a/handler/src/test/java/io/netty/handler/ssl/OpenSslEngineTest.java b/handler/src/test/java/io/netty/handler/ssl/OpenSslEngineTest.java
-deleted file mode 100644
-index 5939b66..0000000
---- a/handler/src/test/java/io/netty/handler/ssl/OpenSslEngineTest.java
-+++ /dev/null
-@@ -1,661 +0,0 @@
--/*
-- * Copyright 2015 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
--
--import io.netty.buffer.UnpooledByteBufAllocator;
--import io.netty.handler.ssl.ApplicationProtocolConfig.Protocol;
--import io.netty.handler.ssl.ApplicationProtocolConfig.SelectedListenerFailureBehavior;
--import io.netty.handler.ssl.ApplicationProtocolConfig.SelectorFailureBehavior;
--import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
--import io.netty.handler.ssl.util.SelfSignedCertificate;
--import io.netty.util.internal.PlatformDependent;
--import org.junit.Assume;
--import org.junit.BeforeClass;
--import org.junit.Test;
--import org.junit.runner.RunWith;
--import org.junit.runners.Parameterized;
--
--import java.nio.ByteBuffer;
--import java.security.AlgorithmConstraints;
--import java.security.AlgorithmParameters;
--import java.security.CryptoPrimitive;
--import java.security.Key;
--import java.util.ArrayList;
--import java.util.Collection;
--import java.util.List;
--import java.util.Set;
--import javax.net.ssl.SSLEngine;
--import javax.net.ssl.SSLEngineResult;
--import javax.net.ssl.SSLException;
--import javax.net.ssl.SSLParameters;
--
--import static io.netty.handler.ssl.OpenSslTestUtils.checkShouldUseKeyManagerFactory;
--import static io.netty.handler.ssl.ReferenceCountedOpenSslEngine.MAX_ENCRYPTED_PACKET_LENGTH;
--import static io.netty.handler.ssl.ReferenceCountedOpenSslEngine.MAX_TLS_RECORD_OVERHEAD_LENGTH;
--import static io.netty.handler.ssl.ReferenceCountedOpenSslEngine.MAX_PLAINTEXT_LENGTH;
--import static io.netty.internal.tcnative.SSL.SSL_CVERIFY_IGNORED;
--import static java.lang.Integer.MAX_VALUE;
--import static org.junit.Assert.assertEquals;
--import static org.junit.Assert.assertFalse;
--import static org.junit.Assert.assertNull;
--import static org.junit.Assert.assertSame;
--import static org.junit.Assert.assertTrue;
--import static org.junit.Assume.assumeTrue;
--
--(a)RunWith(Parameterized.class)
--public class OpenSslEngineTest extends SSLEngineTest {
-- private static final String PREFERRED_APPLICATION_LEVEL_PROTOCOL = "my-protocol-http2";
-- private static final String FALLBACK_APPLICATION_LEVEL_PROTOCOL = "my-protocol-http1_1";
--
-- @Parameterized.Parameters(name = "{index}: bufferType = {0}")
-- public static Collection<Object> data() {
-- List<Object> params = new ArrayList<Object>();
-- for (BufferType type: BufferType.values()) {
-- params.add(type);
+- public final synchronized SSLEngineResult unwrap(ByteBuffer src, ByteBuffer[] dsts) throws SSLException {
+- try {
+- return unwrap(singleSrcBuffer(src), dsts);
+- } finally {
+- resetSingleSrcBuffer();
- }
-- return params;
-- }
--
-- public OpenSslEngineTest(BufferType type) {
-- super(type);
-- }
--
-- @BeforeClass
-- public static void checkOpenSsl() {
-- assumeTrue(OpenSsl.isAvailable());
- }
-
- @Override
-- @Test
-- public void testMutualAuthInvalidIntermediateCASucceedWithOptionalClientAuth() throws Exception {
-- checkShouldUseKeyManagerFactory();
-- super.testMutualAuthInvalidIntermediateCASucceedWithOptionalClientAuth();
+- public final synchronized Runnable getDelegatedTask() {
+- if (isDestroyed()) {
+- return null;
+- }
+- final Runnable task = SSL.getTask(ssl);
+- if (task == null) {
+- return null;
+- }
+- return new Runnable() {
+- @Override
+- public void run() {
+- if (isDestroyed()) {
+- // The engine was destroyed in the meantime, just return.
+- return;
+- }
+- try {
+- task.run();
+- } finally {
+- // The task was run, reset needTask to false so getHandshakeStatus() returns the correct value.
+- needTask = false;
+- }
+- }
+- };
- }
-
- @Override
-- @Test
-- public void testMutualAuthInvalidIntermediateCAFailWithOptionalClientAuth() throws Exception {
-- checkShouldUseKeyManagerFactory();
-- super.testMutualAuthInvalidIntermediateCAFailWithOptionalClientAuth();
-- }
+- public final synchronized void closeInbound() throws SSLException {
+- if (isInboundDone) {
+- return;
+- }
-
-- @Override
-- @Test
-- public void testMutualAuthInvalidIntermediateCAFailWithRequiredClientAuth() throws Exception {
-- checkShouldUseKeyManagerFactory();
-- super.testMutualAuthInvalidIntermediateCAFailWithRequiredClientAuth();
-- }
+- isInboundDone = true;
-
-- @Override
-- @Test
-- public void testMutualAuthValidClientCertChainTooLongFailOptionalClientAuth() throws Exception {
-- checkShouldUseKeyManagerFactory();
-- super.testMutualAuthValidClientCertChainTooLongFailOptionalClientAuth();
-- }
+- if (isOutboundDone()) {
+- // Only call shutdown if there is no outbound data pending.
+- // See https://github.com/netty/netty/issues/6167
+- shutdown();
+- }
-
-- @Override
-- @Test
-- public void testMutualAuthValidClientCertChainTooLongFailRequireClientAuth() throws Exception {
-- checkShouldUseKeyManagerFactory();
-- super.testMutualAuthValidClientCertChainTooLongFailRequireClientAuth();
+- if (handshakeState != HandshakeState.NOT_STARTED && !receivedShutdown) {
+- throw new SSLException(
+- "Inbound closed before receiving peer's close_notify: possible truncation attack?");
+- }
- }
-
- @Override
-- @Test
-- public void testClientHostnameValidationSuccess() throws InterruptedException, SSLException {
-- assumeTrue(OpenSsl.supportsHostnameValidation());
-- super.testClientHostnameValidationSuccess();
+- public final synchronized boolean isInboundDone() {
+- return isInboundDone;
- }
-
- @Override
-- @Test
-- public void testClientHostnameValidationFail() throws InterruptedException, SSLException {
-- assumeTrue(OpenSsl.supportsHostnameValidation());
-- super.testClientHostnameValidationFail();
-- }
--
-- @Test
-- public void testNpn() throws Exception {
-- ApplicationProtocolConfig apn = acceptingNegotiator(Protocol.NPN,
-- PREFERRED_APPLICATION_LEVEL_PROTOCOL);
-- setupHandlers(apn);
-- runTest(PREFERRED_APPLICATION_LEVEL_PROTOCOL);
-- }
--
-- @Test
-- public void testAlpn() throws Exception {
-- assumeTrue(OpenSsl.isAlpnSupported());
-- ApplicationProtocolConfig apn = acceptingNegotiator(Protocol.ALPN,
-- PREFERRED_APPLICATION_LEVEL_PROTOCOL);
-- setupHandlers(apn);
-- runTest(PREFERRED_APPLICATION_LEVEL_PROTOCOL);
-- }
--
-- @Test
-- public void testAlpnCompatibleProtocolsDifferentClientOrder() throws Exception {
-- assumeTrue(OpenSsl.isAlpnSupported());
-- ApplicationProtocolConfig clientApn = acceptingNegotiator(Protocol.ALPN,
-- FALLBACK_APPLICATION_LEVEL_PROTOCOL, PREFERRED_APPLICATION_LEVEL_PROTOCOL);
-- ApplicationProtocolConfig serverApn = acceptingNegotiator(Protocol.ALPN,
-- PREFERRED_APPLICATION_LEVEL_PROTOCOL, FALLBACK_APPLICATION_LEVEL_PROTOCOL);
-- setupHandlers(serverApn, clientApn);
-- assertNull(serverException);
-- runTest(PREFERRED_APPLICATION_LEVEL_PROTOCOL);
-- }
--
-- @Test
-- public void testEnablingAnAlreadyDisabledSslProtocol() throws Exception {
-- testEnablingAnAlreadyDisabledSslProtocol(new String[]{PROTOCOL_SSL_V2_HELLO},
-- new String[]{PROTOCOL_SSL_V2_HELLO, PROTOCOL_TLS_V1_2});
-- }
-- @Test
-- public void testWrapBuffersNoWritePendingError() throws Exception {
-- clientSslCtx = SslContextBuilder.forClient()
-- .trustManager(InsecureTrustManagerFactory.INSTANCE)
-- .sslProvider(sslClientProvider())
-- .build();
-- SelfSignedCertificate ssc = new SelfSignedCertificate();
-- serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey())
-- .sslProvider(sslServerProvider())
-- .build();
-- SSLEngine clientEngine = null;
-- SSLEngine serverEngine = null;
-- try {
-- clientEngine = clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT);
-- serverEngine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT);
-- handshake(clientEngine, serverEngine);
--
-- ByteBuffer src = allocateBuffer(1024 * 10);
-- byte[] data = new byte[src.capacity()];
-- PlatformDependent.threadLocalRandom().nextBytes(data);
-- src.put(data).flip();
-- ByteBuffer dst = allocateBuffer(1);
-- // Try to wrap multiple times so we are more likely to hit the issue.
-- for (int i = 0; i < 100; i++) {
-- src.position(0);
-- dst.position(0);
-- assertSame(SSLEngineResult.Status.BUFFER_OVERFLOW, clientEngine.wrap(src, dst).getStatus());
-- }
-- } finally {
-- cleanupClientSslEngine(clientEngine);
-- cleanupServerSslEngine(serverEngine);
-- }
-- }
--
-- @Test
-- public void testOnlySmallBufferNeededForWrap() throws Exception {
-- clientSslCtx = SslContextBuilder.forClient()
-- .trustManager(InsecureTrustManagerFactory.INSTANCE)
-- .sslProvider(sslClientProvider())
-- .build();
-- SelfSignedCertificate ssc = new SelfSignedCertificate();
-- serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey())
-- .sslProvider(sslServerProvider())
-- .build();
-- SSLEngine clientEngine = null;
-- SSLEngine serverEngine = null;
-- try {
-- clientEngine = clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT);
-- serverEngine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT);
-- handshake(clientEngine, serverEngine);
--
-- // Allocate a buffer which is small enough and set the limit to the capacity to mark its whole content
-- // as readable.
-- int srcLen = 1024;
-- ByteBuffer src = allocateBuffer(srcLen);
--
-- ByteBuffer dstTooSmall = allocateBuffer(
-- src.capacity() + MAX_TLS_RECORD_OVERHEAD_LENGTH - 1);
-- ByteBuffer dst = allocateBuffer(
-- src.capacity() + MAX_TLS_RECORD_OVERHEAD_LENGTH);
--
-- // Check that we fail to wrap if the dst buffers capacity is not at least
-- // src.capacity() + ReferenceCountedOpenSslEngine.MAX_TLS_RECORD_OVERHEAD_LENGTH
-- SSLEngineResult result = clientEngine.wrap(src, dstTooSmall);
-- assertEquals(SSLEngineResult.Status.BUFFER_OVERFLOW, result.getStatus());
-- assertEquals(0, result.bytesConsumed());
-- assertEquals(0, result.bytesProduced());
-- assertEquals(src.remaining(), src.capacity());
-- assertEquals(dst.remaining(), dst.capacity());
--
-- // Check that we can wrap with a dst buffer that has the capacity of
-- // src.capacity() + ReferenceCountedOpenSslEngine.MAX_TLS_RECORD_OVERHEAD_LENGTH
-- result = clientEngine.wrap(src, dst);
-- assertEquals(SSLEngineResult.Status.OK, result.getStatus());
-- assertEquals(srcLen, result.bytesConsumed());
-- assertEquals(0, src.remaining());
-- assertTrue(result.bytesProduced() > srcLen);
-- assertEquals(src.capacity() - result.bytesConsumed(), src.remaining());
-- assertEquals(dst.capacity() - result.bytesProduced(), dst.remaining());
-- } finally {
-- cleanupClientSslEngine(clientEngine);
-- cleanupServerSslEngine(serverEngine);
-- }
-- }
--
-- @Test
-- public void testNeededDstCapacityIsCorrectlyCalculated() throws Exception {
-- clientSslCtx = SslContextBuilder.forClient()
-- .trustManager(InsecureTrustManagerFactory.INSTANCE)
-- .sslProvider(sslClientProvider())
-- .build();
-- SelfSignedCertificate ssc = new SelfSignedCertificate();
-- serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey())
-- .sslProvider(sslServerProvider())
-- .build();
-- SSLEngine clientEngine = null;
-- SSLEngine serverEngine = null;
-- try {
-- clientEngine = clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT);
-- serverEngine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT);
-- handshake(clientEngine, serverEngine);
--
-- ByteBuffer src = allocateBuffer(1024);
-- ByteBuffer src2 = src.duplicate();
--
-- ByteBuffer dst = allocateBuffer(src.capacity()
-- + MAX_TLS_RECORD_OVERHEAD_LENGTH);
--
-- SSLEngineResult result = clientEngine.wrap(new ByteBuffer[] { src, src2 }, dst);
-- assertEquals(SSLEngineResult.Status.BUFFER_OVERFLOW, result.getStatus());
-- assertEquals(0, src.position());
-- assertEquals(0, src2.position());
-- assertEquals(0, dst.position());
-- assertEquals(0, result.bytesConsumed());
-- assertEquals(0, result.bytesProduced());
-- } finally {
-- cleanupClientSslEngine(clientEngine);
-- cleanupServerSslEngine(serverEngine);
-- }
-- }
--
-- @Test
-- public void testSrcsLenOverFlowCorrectlyHandled() throws Exception {
-- clientSslCtx = SslContextBuilder.forClient()
-- .trustManager(InsecureTrustManagerFactory.INSTANCE)
-- .sslProvider(sslClientProvider())
-- .build();
-- SelfSignedCertificate ssc = new SelfSignedCertificate();
-- serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey())
-- .sslProvider(sslServerProvider())
-- .build();
-- SSLEngine clientEngine = null;
-- SSLEngine serverEngine = null;
-- try {
-- clientEngine = clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT);
-- serverEngine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT);
-- handshake(clientEngine, serverEngine);
+- public final synchronized void closeOutbound() {
+- if (outboundClosed) {
+- return;
+- }
-
-- ByteBuffer src = allocateBuffer(1024);
-- List<ByteBuffer> srcList = new ArrayList<ByteBuffer>();
-- long srcsLen = 0;
-- long maxLen = ((long) MAX_VALUE) * 2;
+- outboundClosed = true;
-
-- while (srcsLen < maxLen) {
-- ByteBuffer dup = src.duplicate();
-- srcList.add(dup);
-- srcsLen += dup.capacity();
+- if (handshakeState != HandshakeState.NOT_STARTED && !isDestroyed()) {
+- int mode = SSL.getShutdown(ssl);
+- if ((mode & SSL.SSL_SENT_SHUTDOWN) != SSL.SSL_SENT_SHUTDOWN) {
+- doSSLShutdown();
- }
+- } else {
+- // engine closing before initial handshake
+- shutdown();
+- }
+- }
-
-- ByteBuffer[] srcs = srcList.toArray(new ByteBuffer[srcList.size()]);
--
-- ByteBuffer dst = allocateBuffer(MAX_ENCRYPTED_PACKET_LENGTH - 1);
--
-- SSLEngineResult result = clientEngine.wrap(srcs, dst);
-- assertEquals(SSLEngineResult.Status.BUFFER_OVERFLOW, result.getStatus());
--
-- for (ByteBuffer buffer : srcs) {
-- assertEquals(0, buffer.position());
+- /**
+- * Attempt to call {@link SSL#shutdownSSL(long)}.
+- * @return {@code false} if the call to {@link SSL#shutdownSSL(long)} was not attempted or returned an error.
+- */
+- private boolean doSSLShutdown() {
+- if (SSL.isInInit(ssl) != 0) {
+- // Only try to call SSL_shutdown if we are not in the init state anymore.
+- // Otherwise we will see 'error:140E0197:SSL routines:SSL_shutdown:shutdown while in init' in our logs.
+- //
+- // See also http://hg.nginx.org/nginx/rev/062c189fee20
+- return false;
+- }
+- int err = SSL.shutdownSSL(ssl);
+- if (err < 0) {
+- int sslErr = SSL.getError(ssl, err);
+- if (sslErr == SSL.SSL_ERROR_SYSCALL || sslErr == SSL.SSL_ERROR_SSL) {
+- if (logger.isDebugEnabled()) {
+- int error = SSL.getLastErrorNumber();
+- logger.debug("SSL_shutdown failed: OpenSSL error: {} {}", error, SSL.getErrorString(error));
+- }
+- // There was an internal error -- shutdown
+- shutdown();
+- return false;
- }
-- assertEquals(0, dst.position());
-- assertEquals(0, result.bytesConsumed());
-- assertEquals(0, result.bytesProduced());
-- } finally {
-- cleanupClientSslEngine(clientEngine);
-- cleanupServerSslEngine(serverEngine);
+- SSL.clearError();
- }
+- return true;
- }
-
-- @Test
-- public void testCalculateOutNetBufSizeOverflow() {
-- assertEquals(MAX_ENCRYPTED_PACKET_LENGTH,
-- ReferenceCountedOpenSslEngine.calculateOutNetBufSize(MAX_VALUE, 1));
-- }
--
-- @Test
-- public void testCalculateOutNetBufSize0() {
-- assertEquals(MAX_TLS_RECORD_OVERHEAD_LENGTH,
-- ReferenceCountedOpenSslEngine.calculateOutNetBufSize(0, 1));
+- @Override
+- public final synchronized boolean isOutboundDone() {
+- // Check if there is anything left in the outbound buffer.
+- // We need to ensure we only call SSL.pendingWrittenBytesInBIO(...) if the engine was not destroyed yet.
+- return outboundClosed && (networkBIO == 0 || SSL.bioLengthNonApplication(networkBIO) == 0);
- }
-
-- @Test
-- public void testCalculateOutNetBufSizeMaxEncryptedPacketLength() {
-- assertEquals(MAX_ENCRYPTED_PACKET_LENGTH,
-- ReferenceCountedOpenSslEngine.calculateOutNetBufSize(MAX_ENCRYPTED_PACKET_LENGTH + 1, 2));
+- @Override
+- public final String[] getSupportedCipherSuites() {
+- return OpenSsl.AVAILABLE_CIPHER_SUITES.toArray(new String[0]);
- }
-
- @Override
-- protected void mySetupMutualAuthServerInitSslHandler(SslHandler handler) {
-- ReferenceCountedOpenSslEngine engine = (ReferenceCountedOpenSslEngine) handler.engine();
-- engine.setVerify(SSL_CVERIFY_IGNORED, 1);
-- }
--
-- @Test
-- public void testWrapWithDifferentSizesTLSv1() throws Exception {
-- clientSslCtx = SslContextBuilder.forClient()
-- .trustManager(InsecureTrustManagerFactory.INSTANCE)
-- .sslProvider(sslClientProvider())
-- .build();
-- SelfSignedCertificate ssc = new SelfSignedCertificate();
-- serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey())
-- .sslProvider(sslServerProvider())
-- .build();
--
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ADH-AES128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "AES128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ECDHE-RSA-AES128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ADH-CAMELLIA128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "AECDH-AES128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "AECDH-DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "CAMELLIA128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "DHE-RSA-AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "SEED-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "RC4-MD5");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ADH-AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ADH-SEED-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ADH-DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "EDH-RSA-DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ADH-RC4-MD5");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "IDEA-CBC-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "DHE-RSA-AES128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "RC4-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "CAMELLIA256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "AECDH-RC4-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "DHE-RSA-SEED-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "AECDH-AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ECDHE-RSA-DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ADH-CAMELLIA256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "DHE-RSA-CAMELLIA256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ECDHE-RSA-AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "DHE-RSA-CAMELLIA128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ECDHE-RSA-RC4-SHA");
-- }
--
-- @Test
-- public void testWrapWithDifferentSizesTLSv1_1() throws Exception {
-- clientSslCtx = SslContextBuilder.forClient()
-- .trustManager(InsecureTrustManagerFactory.INSTANCE)
-- .sslProvider(sslClientProvider())
-- .build();
-- SelfSignedCertificate ssc = new SelfSignedCertificate();
-- serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey())
-- .sslProvider(sslServerProvider())
-- .build();
--
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "ECDHE-RSA-AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "DHE-RSA-AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "DHE-RSA-CAMELLIA256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "ADH-CAMELLIA256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "ADH-AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "CAMELLIA256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "AECDH-AES128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "DHE-RSA-CAMELLIA128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "ECDHE-RSA-AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "ADH-AES128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "ADH-SEED-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "ADH-CAMELLIA128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "SEED-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "CAMELLIA128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "IDEA-CBC-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "AECDH-RC4-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "ADH-RC4-MD5");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "RC4-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "ECDHE-RSA-DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "EDH-RSA-DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "AECDH-DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "ADH-DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "DES-CBC3-SHA");
-- }
--
-- @Test
-- public void testWrapWithDifferentSizesTLSv1_2() throws Exception {
-- clientSslCtx = SslContextBuilder.forClient()
-- .trustManager(InsecureTrustManagerFactory.INSTANCE)
-- .sslProvider(sslClientProvider())
-- .build();
-- SelfSignedCertificate ssc = new SelfSignedCertificate();
-- serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey())
-- .sslProvider(sslServerProvider())
-- .build();
--
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ADH-AES128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "AES128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ECDHE-RSA-AES128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ADH-CAMELLIA128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "DHE-RSA-AES256-GCM-SHA384");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "AECDH-AES128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "AES128-GCM-SHA256");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "DHE-RSA-AES128-GCM-SHA256");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ECDHE-RSA-AES256-SHA384");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "AECDH-DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "AES256-GCM-SHA384");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "AES256-SHA256");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ECDHE-RSA-AES128-GCM-SHA256");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ECDHE-RSA-AES128-SHA256");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "CAMELLIA128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "DHE-RSA-AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "SEED-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "RC4-MD5");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ADH-AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ADH-SEED-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "DHE-RSA-AES128-SHA256");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ADH-DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "EDH-RSA-DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ADH-RC4-MD5");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "IDEA-CBC-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "DHE-RSA-AES128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "RC4-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "CAMELLIA256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ADH-AES128-GCM-SHA256");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "AES128-SHA256");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "AECDH-RC4-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ADH-AES256-GCM-SHA384");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "DHE-RSA-SEED-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "DHE-RSA-AES256-SHA256");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "AECDH-AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ECDHE-RSA-DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ADH-CAMELLIA256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ECDHE-RSA-AES256-GCM-SHA384");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "DHE-RSA-CAMELLIA256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ADH-AES256-SHA256");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ADH-AES128-SHA256");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ECDHE-RSA-AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "DHE-RSA-CAMELLIA128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ECDHE-RSA-RC4-SHA");
-- }
--
-- @Test
-- public void testWrapWithDifferentSizesSSLv3() throws Exception {
-- clientSslCtx = SslContextBuilder.forClient()
-- .trustManager(InsecureTrustManagerFactory.INSTANCE)
-- .sslProvider(sslClientProvider())
-- .build();
-- SelfSignedCertificate ssc = new SelfSignedCertificate();
-- serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey())
-- .sslProvider(sslServerProvider())
-- .build();
--
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "ADH-AES128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "AES128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "ADH-CAMELLIA128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "AECDH-AES128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "AECDH-DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "CAMELLIA128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "DHE-RSA-AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "SEED-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "RC4-MD5");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "ADH-AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "ADH-SEED-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "ADH-DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "EDH-RSA-DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "ADH-RC4-MD5");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "IDEA-CBC-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "DHE-RSA-AES128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "RC4-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "CAMELLIA256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "AECDH-RC4-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "DHE-RSA-SEED-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "AECDH-AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "ECDHE-RSA-DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "ADH-CAMELLIA256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "DHE-RSA-CAMELLIA256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "DHE-RSA-CAMELLIA128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "ECDHE-RSA-RC4-SHA");
-- }
--
-- private void testWrapWithDifferentSizes(String protocol, String cipher) throws Exception {
-- assumeTrue(OpenSsl.SUPPORTED_PROTOCOLS_SET.contains(protocol));
-- if (!OpenSsl.isCipherSuiteAvailable(cipher)) {
-- return;
+- public final String[] getEnabledCipherSuites() {
+- final String[] extraCiphers;
+- final String[] enabled;
+- synchronized (this) {
+- if (!isDestroyed()) {
+- enabled = SSL.getCiphers(ssl);
+- int opts = SSL.getOptions(ssl);
+- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_TLSv1_3, PROTOCOL_TLS_V1_3)) {
+- extraCiphers = OpenSsl.EXTRA_SUPPORTED_TLS_1_3_CIPHERS;
+- } else {
+- extraCiphers = EmptyArrays.EMPTY_STRINGS;
+- }
+- } else {
+- return EmptyArrays.EMPTY_STRINGS;
+- }
- }
--
-- SSLEngine clientEngine = null;
-- SSLEngine serverEngine = null;
-- try {
-- clientEngine = clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT);
-- serverEngine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT);
-- clientEngine.setEnabledCipherSuites(new String[] { cipher });
-- clientEngine.setEnabledProtocols(new String[] { protocol });
-- serverEngine.setEnabledCipherSuites(new String[] { cipher });
-- serverEngine.setEnabledProtocols(new String[] { protocol });
--
-- try {
-- handshake(clientEngine, serverEngine);
-- } catch (SSLException e) {
-- if (e.getMessage().contains("unsupported protocol")) {
-- Assume.assumeNoException(protocol + " not supported with cipher " + cipher, e);
+- if (enabled == null) {
+- return EmptyArrays.EMPTY_STRINGS;
+- } else {
+- Set<String> enabledSet = new LinkedHashSet<String>(enabled.length + extraCiphers.length);
+- synchronized (this) {
+- for (int i = 0; i < enabled.length; i++) {
+- String mapped = toJavaCipherSuite(enabled[i]);
+- final String cipher = mapped == null ? enabled[i] : mapped;
+- if (!OpenSsl.isTlsv13Supported() && SslUtils.isTLSv13Cipher(cipher)) {
+- continue;
+- }
+- enabledSet.add(cipher);
- }
-- throw e;
+- Collections.addAll(enabledSet, extraCiphers);
- }
--
-- int srcLen = 64;
-- do {
-- testWrapDstBigEnough(clientEngine, srcLen);
-- srcLen += 64;
-- } while (srcLen < MAX_PLAINTEXT_LENGTH);
--
-- testWrapDstBigEnough(clientEngine, MAX_PLAINTEXT_LENGTH);
-- } finally {
-- cleanupClientSslEngine(clientEngine);
-- cleanupServerSslEngine(serverEngine);
+- return enabledSet.toArray(new String[0]);
- }
- }
-
-- private void testWrapDstBigEnough(SSLEngine engine, int srcLen) throws SSLException {
-- ByteBuffer src = allocateBuffer(srcLen);
-- ByteBuffer dst = allocateBuffer(srcLen + MAX_TLS_RECORD_OVERHEAD_LENGTH);
--
-- SSLEngineResult result = engine.wrap(src, dst);
-- assertEquals(SSLEngineResult.Status.OK, result.getStatus());
-- int consumed = result.bytesConsumed();
-- int produced = result.bytesProduced();
-- assertEquals(srcLen, consumed);
-- assertTrue(produced > consumed);
+- @Override
+- public final void setEnabledCipherSuites(String[] cipherSuites) {
+- checkNotNull(cipherSuites, "cipherSuites");
-
-- dst.flip();
-- assertEquals(produced, dst.remaining());
-- assertFalse(src.hasRemaining());
-- }
+- final StringBuilder buf = new StringBuilder();
+- final StringBuilder bufTLSv13 = new StringBuilder();
-
-- @Test
-- public void testSNIMatchersDoesNotThrow() throws Exception {
-- assumeTrue(PlatformDependent.javaVersion() >= 8);
-- SelfSignedCertificate ssc = new SelfSignedCertificate();
-- serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey())
-- .sslProvider(sslServerProvider())
-- .build();
+- CipherSuiteConverter.convertToCipherStrings(Arrays.asList(cipherSuites), buf, bufTLSv13, OpenSsl.isBoringSSL());
+- final String cipherSuiteSpec = buf.toString();
+- final String cipherSuiteSpecTLSv13 = bufTLSv13.toString();
-
-- SSLEngine engine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT);
-- try {
-- SSLParameters parameters = new SSLParameters();
-- Java8SslTestUtils.setSNIMatcher(parameters);
-- engine.setSSLParameters(parameters);
-- } finally {
-- cleanupServerSslEngine(engine);
-- ssc.delete();
+- if (!OpenSsl.isTlsv13Supported() && !cipherSuiteSpecTLSv13.isEmpty()) {
+- throw new IllegalArgumentException("TLSv1.3 is not supported by this java version.");
- }
-- }
--
-- @Test(expected = IllegalArgumentException.class)
-- public void testAlgorithmConstraintsThrows() throws Exception {
-- SelfSignedCertificate ssc = new SelfSignedCertificate();
-- serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey())
-- .sslProvider(sslServerProvider())
-- .build();
--
-- SSLEngine engine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT);
-- try {
-- SSLParameters parameters = new SSLParameters();
-- parameters.setAlgorithmConstraints(new AlgorithmConstraints() {
-- @Override
-- public boolean permits(
-- Set<CryptoPrimitive> primitives, String algorithm, AlgorithmParameters parameters) {
-- return false;
-- }
+- synchronized (this) {
+- if (!isDestroyed()) {
+- // TODO: Should we also adjust the protocols based on if there are any ciphers left that can be used
+- // for TLSv1.3 or for previor SSL/TLS versions ?
+- try {
+- // Set non TLSv1.3 ciphers.
+- SSL.setCipherSuites(ssl, cipherSuiteSpec, false);
-
-- @Override
-- public boolean permits(Set<CryptoPrimitive> primitives, Key key) {
-- return false;
-- }
+- if (OpenSsl.isTlsv13Supported()) {
+- // Set TLSv1.3 ciphers.
+- SSL.setCipherSuites(ssl, cipherSuiteSpecTLSv13, true);
+- }
-
-- @Override
-- public boolean permits(
-- Set<CryptoPrimitive> primitives, String algorithm, Key key, AlgorithmParameters parameters) {
-- return false;
+- } catch (Exception e) {
+- throw new IllegalStateException("failed to enable cipher suites: " + cipherSuiteSpec, e);
- }
-- });
-- engine.setSSLParameters(parameters);
-- } finally {
-- cleanupServerSslEngine(engine);
-- ssc.delete();
+- } else {
+- throw new IllegalStateException("failed to enable cipher suites: " + cipherSuiteSpec);
+- }
- }
- }
-
- @Override
-- protected SslProvider sslClientProvider() {
-- return SslProvider.OPENSSL;
+- public final String[] getSupportedProtocols() {
+- return OpenSsl.SUPPORTED_PROTOCOLS_SET.toArray(new String[0]);
- }
-
- @Override
-- protected SslProvider sslServerProvider() {
-- return SslProvider.OPENSSL;
-- }
--
-- private static ApplicationProtocolConfig acceptingNegotiator(Protocol protocol,
-- String... supportedProtocols) {
-- return new ApplicationProtocolConfig(protocol,
-- SelectorFailureBehavior.NO_ADVERTISE,
-- SelectedListenerFailureBehavior.ACCEPT,
-- supportedProtocols);
-- }
--}
-diff --git a/handler/src/test/java/io/netty/handler/ssl/OpenSslJdkSslEngineInteroptTest.java b/handler/src/test/java/io/netty/handler/ssl/OpenSslJdkSslEngineInteroptTest.java
-deleted file mode 100644
-index f63a16f..0000000
---- a/handler/src/test/java/io/netty/handler/ssl/OpenSslJdkSslEngineInteroptTest.java
-+++ /dev/null
-@@ -1,114 +0,0 @@
--/*
-- * Copyright 2016 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
--
--import org.junit.BeforeClass;
--import org.junit.Ignore;
--import org.junit.Test;
--
--import javax.net.ssl.SSLException;
--import org.junit.runner.RunWith;
--import org.junit.runners.Parameterized;
--
--import java.util.ArrayList;
--import java.util.Collection;
--import java.util.List;
--
--import static io.netty.handler.ssl.OpenSslTestUtils.checkShouldUseKeyManagerFactory;
--import static org.junit.Assume.assumeTrue;
--
--(a)RunWith(Parameterized.class)
--public class OpenSslJdkSslEngineInteroptTest extends SSLEngineTest {
+- public final String[] getEnabledProtocols() {
+- List<String> enabled = new ArrayList<String>(6);
+- // Seems like there is no way to explicit disable SSLv2Hello in openssl so it is always enabled
+- enabled.add(PROTOCOL_SSL_V2_HELLO);
-
-- @Parameterized.Parameters(name = "{index}: bufferType = {0}")
-- public static Collection<Object> data() {
-- List<Object> params = new ArrayList<Object>();
-- for (BufferType type: BufferType.values()) {
-- params.add(type);
+- int opts;
+- synchronized (this) {
+- if (!isDestroyed()) {
+- opts = SSL.getOptions(ssl);
+- } else {
+- return enabled.toArray(new String[0]);
+- }
- }
-- return params;
-- }
--
-- public OpenSslJdkSslEngineInteroptTest(BufferType type) {
-- super(type);
+- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_TLSv1, PROTOCOL_TLS_V1)) {
+- enabled.add(PROTOCOL_TLS_V1);
+- }
+- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_TLSv1_1, PROTOCOL_TLS_V1_1)) {
+- enabled.add(PROTOCOL_TLS_V1_1);
+- }
+- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_TLSv1_2, PROTOCOL_TLS_V1_2)) {
+- enabled.add(PROTOCOL_TLS_V1_2);
+- }
+- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_TLSv1_3, PROTOCOL_TLS_V1_3)) {
+- enabled.add(PROTOCOL_TLS_V1_3);
+- }
+- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_SSLv2, PROTOCOL_SSL_V2)) {
+- enabled.add(PROTOCOL_SSL_V2);
+- }
+- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_SSLv3, PROTOCOL_SSL_V3)) {
+- enabled.add(PROTOCOL_SSL_V3);
+- }
+- return enabled.toArray(new String[0]);
- }
-
-- @BeforeClass
-- public static void checkOpenSsl() {
-- assumeTrue(OpenSsl.isAvailable());
+- private static boolean isProtocolEnabled(int opts, int disableMask, String protocolString) {
+- // We also need to check if the actual protocolString is supported as depending on the openssl API
+- // implementations it may use a disableMask of 0 (BoringSSL is doing this for example).
+- return (opts & disableMask) == 0 && OpenSsl.SUPPORTED_PROTOCOLS_SET.contains(protocolString);
- }
-
+- /**
+- * {@inheritDoc}
+- * TLS doesn't support a way to advertise non-contiguous versions from the client's perspective, and the client
+- * just advertises the max supported version. The TLS protocol also doesn't support all different combinations of
+- * discrete protocols, and instead assumes contiguous ranges. OpenSSL has some unexpected behavior
+- * (e.g. handshake failures) if non-contiguous protocols are used even where there is a compatible set of protocols
+- * and ciphers. For these reasons this method will determine the minimum protocol and the maximum protocol and
+- * enabled a contiguous range from [min protocol, max protocol] in OpenSSL.
+- */
- @Override
-- protected SslProvider sslClientProvider() {
-- return SslProvider.OPENSSL;
-- }
+- public final void setEnabledProtocols(String[] protocols) {
+- if (protocols == null) {
+- // This is correct from the API docs
+- throw new IllegalArgumentException();
+- }
+- int minProtocolIndex = OPENSSL_OP_NO_PROTOCOLS.length;
+- int maxProtocolIndex = 0;
+- for (String p: protocols) {
+- if (!OpenSsl.SUPPORTED_PROTOCOLS_SET.contains(p)) {
+- throw new IllegalArgumentException("Protocol " + p + " is not supported.");
+- }
+- if (p.equals(PROTOCOL_SSL_V2)) {
+- if (minProtocolIndex > OPENSSL_OP_NO_PROTOCOL_INDEX_SSLV2) {
+- minProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_SSLV2;
+- }
+- if (maxProtocolIndex < OPENSSL_OP_NO_PROTOCOL_INDEX_SSLV2) {
+- maxProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_SSLV2;
+- }
+- } else if (p.equals(PROTOCOL_SSL_V3)) {
+- if (minProtocolIndex > OPENSSL_OP_NO_PROTOCOL_INDEX_SSLV3) {
+- minProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_SSLV3;
+- }
+- if (maxProtocolIndex < OPENSSL_OP_NO_PROTOCOL_INDEX_SSLV3) {
+- maxProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_SSLV3;
+- }
+- } else if (p.equals(PROTOCOL_TLS_V1)) {
+- if (minProtocolIndex > OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1) {
+- minProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1;
+- }
+- if (maxProtocolIndex < OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1) {
+- maxProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1;
+- }
+- } else if (p.equals(PROTOCOL_TLS_V1_1)) {
+- if (minProtocolIndex > OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_1) {
+- minProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_1;
+- }
+- if (maxProtocolIndex < OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_1) {
+- maxProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_1;
+- }
+- } else if (p.equals(PROTOCOL_TLS_V1_2)) {
+- if (minProtocolIndex > OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_2) {
+- minProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_2;
+- }
+- if (maxProtocolIndex < OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_2) {
+- maxProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_2;
+- }
+- } else if (p.equals(PROTOCOL_TLS_V1_3)) {
+- if (minProtocolIndex > OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_3) {
+- minProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_3;
+- }
+- if (maxProtocolIndex < OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_3) {
+- maxProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_3;
+- }
+- }
+- }
+- synchronized (this) {
+- if (!isDestroyed()) {
+- // Clear out options which disable protocols
+- SSL.clearOptions(ssl, SSL.SSL_OP_NO_SSLv2 | SSL.SSL_OP_NO_SSLv3 | SSL.SSL_OP_NO_TLSv1 |
+- SSL.SSL_OP_NO_TLSv1_1 | SSL.SSL_OP_NO_TLSv1_2 | SSL.SSL_OP_NO_TLSv1_3);
-
-- @Override
-- protected SslProvider sslServerProvider() {
-- return SslProvider.JDK;
-- }
+- int opts = 0;
+- for (int i = 0; i < minProtocolIndex; ++i) {
+- opts |= OPENSSL_OP_NO_PROTOCOLS[i];
+- }
+- assert maxProtocolIndex != MAX_VALUE;
+- for (int i = maxProtocolIndex + 1; i < OPENSSL_OP_NO_PROTOCOLS.length; ++i) {
+- opts |= OPENSSL_OP_NO_PROTOCOLS[i];
+- }
-
-- @Ignore /* Does the JDK support a "max certificate chain length"? */
-- @Override
-- public void testMutualAuthValidClientCertChainTooLongFailOptionalClientAuth() throws Exception {
+- // Disable protocols we do not want
+- SSL.setOptions(ssl, opts);
+- } else {
+- throw new IllegalStateException("failed to enable protocols: " + Arrays.asList(protocols));
+- }
+- }
- }
-
-- @Ignore /* Does the JDK support a "max certificate chain length"? */
- @Override
-- public void testMutualAuthValidClientCertChainTooLongFailRequireClientAuth() throws Exception {
+- public final SSLSession getSession() {
+- return session;
- }
-
- @Override
-- @Test
-- public void testMutualAuthInvalidIntermediateCASucceedWithOptionalClientAuth() throws Exception {
-- checkShouldUseKeyManagerFactory();
-- super.testMutualAuthInvalidIntermediateCASucceedWithOptionalClientAuth();
-- }
+- public final synchronized void beginHandshake() throws SSLException {
+- switch (handshakeState) {
+- case STARTED_IMPLICITLY:
+- checkEngineClosed();
-
-- @Override
-- @Test
-- public void testMutualAuthInvalidIntermediateCAFailWithOptionalClientAuth() throws Exception {
-- checkShouldUseKeyManagerFactory();
-- super.testMutualAuthInvalidIntermediateCAFailWithOptionalClientAuth();
-- }
+- // A user did not start handshake by calling this method by him/herself,
+- // but handshake has been started already by wrap() or unwrap() implicitly.
+- // Because it's the user's first time to call this method, it is unfair to
+- // raise an exception. From the user's standpoint, he or she never asked
+- // for renegotiation.
-
-- @Override
-- @Test
-- public void testMutualAuthInvalidIntermediateCAFailWithRequiredClientAuth() throws Exception {
-- checkShouldUseKeyManagerFactory();
-- super.testMutualAuthInvalidIntermediateCAFailWithRequiredClientAuth();
+- handshakeState = HandshakeState.STARTED_EXPLICITLY; // Next time this method is invoked by the user,
+- calculateMaxWrapOverhead();
+- // we should raise an exception.
+- break;
+- case STARTED_EXPLICITLY:
+- // Nothing to do as the handshake is not done yet.
+- break;
+- case FINISHED:
+- throw new SSLException("renegotiation unsupported");
+- case NOT_STARTED:
+- handshakeState = HandshakeState.STARTED_EXPLICITLY;
+- if (handshake() == NEED_TASK) {
+- // Set needTask to true so getHandshakeStatus() will return the correct value.
+- needTask = true;
+- }
+- calculateMaxWrapOverhead();
+- break;
+- default:
+- throw new Error();
+- }
- }
-
-- @Override
-- @Test
-- public void testClientHostnameValidationSuccess() throws InterruptedException, SSLException {
-- assumeTrue(OpenSsl.supportsHostnameValidation());
-- super.testClientHostnameValidationSuccess();
+- private void checkEngineClosed() throws SSLException {
+- if (isDestroyed()) {
+- throw new SSLException("engine closed");
+- }
- }
-
-- @Override
-- @Test
-- public void testClientHostnameValidationFail() throws InterruptedException, SSLException {
-- assumeTrue(OpenSsl.supportsHostnameValidation());
-- super.testClientHostnameValidationFail();
+- private static SSLEngineResult.HandshakeStatus pendingStatus(int pendingStatus) {
+- // Depending on if there is something left in the BIO we need to WRAP or UNWRAP
+- return pendingStatus > 0 ? NEED_WRAP : NEED_UNWRAP;
- }
-
-- @Override
-- protected boolean mySetupMutualAuthServerIsValidServerException(Throwable cause) {
-- // TODO(scott): work around for a JDK issue. The exception should be SSLHandshakeException.
-- return super.mySetupMutualAuthServerIsValidServerException(cause) || causedBySSLException(cause);
+- private static boolean isEmpty(Object[] arr) {
+- return arr == null || arr.length == 0;
- }
--}
-diff --git a/handler/src/test/java/io/netty/handler/ssl/OpenSslRenegotiateSmallBIOTest.java b/handler/src/test/java/io/netty/handler/ssl/OpenSslRenegotiateSmallBIOTest.java
-deleted file mode 100644
-index 3959e64..0000000
---- a/handler/src/test/java/io/netty/handler/ssl/OpenSslRenegotiateSmallBIOTest.java
-+++ /dev/null
-@@ -1,23 +0,0 @@
--/*
-- * Copyright 2017 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
-
--public class OpenSslRenegotiateSmallBIOTest extends OpenSslRenegotiateTest {
-- @Override
-- protected void initSslServerContext(SslContext context) {
-- ((ReferenceCountedOpenSslContext) context).setBioNonApplicationBufferSize(1);
+- private static boolean isEmpty(byte[] cert) {
+- return cert == null || cert.length == 0;
- }
--}
-diff --git a/handler/src/test/java/io/netty/handler/ssl/OpenSslRenegotiateTest.java b/handler/src/test/java/io/netty/handler/ssl/OpenSslRenegotiateTest.java
-deleted file mode 100644
-index 8f3dfee..0000000
---- a/handler/src/test/java/io/netty/handler/ssl/OpenSslRenegotiateTest.java
-+++ /dev/null
-@@ -1,36 +0,0 @@
--/*
-- * Copyright 2015 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
-
--import org.junit.BeforeClass;
+- private SSLEngineResult.HandshakeStatus handshakeException() throws SSLException {
+- if (SSL.bioLengthNonApplication(networkBIO) > 0) {
+- // There is something pending, we need to consume it first via a WRAP so we don't loose anything.
+- return NEED_WRAP;
+- }
+-
+- Throwable exception = pendingException;
+- assert exception != null;
+- pendingException = null;
+- shutdown();
+- if (exception instanceof SSLHandshakeException) {
+- throw (SSLHandshakeException) exception;
+- }
+- SSLHandshakeException e = new SSLHandshakeException("General OpenSslEngine problem");
+- e.initCause(exception);
+- throw e;
+- }
-
--import static org.junit.Assume.assumeFalse;
--import static org.junit.Assume.assumeTrue;
+- /**
+- * Should be called if the handshake will be failed due a callback that throws an exception.
+- * This cause will then be used to give more details as part of the {@link SSLHandshakeException}.
+- */
+- final void initHandshakeException(Throwable cause) {
+- if (pendingException == null) {
+- pendingException = cause;
+- } else {
+- ThrowableUtil.addSuppressed(pendingException, cause);
+- }
+- }
-
--public class OpenSslRenegotiateTest extends RenegotiateTest {
+- private SSLEngineResult.HandshakeStatus handshake() throws SSLException {
+- if (needTask) {
+- return NEED_TASK;
+- }
+- if (handshakeState == HandshakeState.FINISHED) {
+- return FINISHED;
+- }
-
-- @BeforeClass
-- public static void checkOpenSsl() {
-- assumeTrue(OpenSsl.isAvailable());
-- // BoringSSL does not support renegotiation intentionally.
-- assumeFalse("BoringSSL".equals(OpenSsl.versionString()));
-- }
+- checkEngineClosed();
-
-- @Override
-- protected SslProvider serverSslProvider() {
-- return SslProvider.OPENSSL;
-- }
--}
-diff --git a/handler/src/test/java/io/netty/handler/ssl/OpenSslServerContextTest.java b/handler/src/test/java/io/netty/handler/ssl/OpenSslServerContextTest.java
-deleted file mode 100644
-index f22d045..0000000
---- a/handler/src/test/java/io/netty/handler/ssl/OpenSslServerContextTest.java
-+++ /dev/null
-@@ -1,39 +0,0 @@
--/*
-- * Copyright 2016 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
+- if (pendingException != null) {
+- // Let's call SSL.doHandshake(...) again in case there is some async operation pending that would fill the
+- // outbound buffer.
+- if (SSL.doHandshake(ssl) <= 0) {
+- // Clear any error that was put on the stack by the handshake
+- SSL.clearError();
+- }
+- return handshakeException();
+- }
-
--package io.netty.handler.ssl;
+- // Adding the OpenSslEngine to the OpenSslEngineMap so it can be used in the AbstractCertificateVerifier.
+- engineMap.add(this);
+- if (lastAccessed == -1) {
+- lastAccessed = System.currentTimeMillis();
+- }
-
--import org.junit.Assume;
--import org.junit.BeforeClass;
+- int code = SSL.doHandshake(ssl);
+- if (code <= 0) {
+- int sslError = SSL.getError(ssl, code);
+- if (sslError == SSL.SSL_ERROR_WANT_READ || sslError == SSL.SSL_ERROR_WANT_WRITE) {
+- return pendingStatus(SSL.bioLengthNonApplication(networkBIO));
+- }
-
--import javax.net.ssl.SSLException;
--import java.io.File;
+- if (sslError == SSL.SSL_ERROR_WANT_X509_LOOKUP ||
+- sslError == SSL.SSL_ERROR_WANT_CERTIFICATE_VERIFY ||
+- sslError == SSL.SSL_ERROR_WANT_PRIVATE_KEY_OPERATION) {
+- return NEED_TASK;
+- }
-
--import static org.junit.Assume.assumeTrue;
+- // Check if we have a pending exception that was created during the handshake and if so throw it after
+- // shutdown the connection.
+- if (pendingException != null) {
+- return handshakeException();
+- }
-
--public class OpenSslServerContextTest extends SslContextTest {
+- // Everything else is considered as error
+- throw shutdownWithError("SSL_do_handshake", sslError);
+- }
+- // We have produced more data as part of the handshake if this is the case the user should call wrap(...)
+- if (SSL.bioLengthNonApplication(networkBIO) > 0) {
+- return NEED_WRAP;
+- }
+- // if SSL_do_handshake returns > 0 or sslError == SSL.SSL_ERROR_NAME it means the handshake was finished.
+- session.handshakeFinished();
+- return FINISHED;
+- }
-
-- @BeforeClass
-- public static void checkOpenSsl() {
-- assumeTrue(OpenSsl.isAvailable());
+- private SSLEngineResult.HandshakeStatus mayFinishHandshake(SSLEngineResult.HandshakeStatus status)
+- throws SSLException {
+- if (status == NOT_HANDSHAKING && handshakeState != HandshakeState.FINISHED) {
+- // If the status was NOT_HANDSHAKING and we not finished the handshake we need to call
+- // SSL_do_handshake() again
+- return handshake();
+- }
+- return status;
- }
-
- @Override
-- protected SslContext newServerContext(File crtFile, File keyFile, String pass) throws SSLException {
-- Assume.assumeTrue(OpenSsl.isAvailable());
-- return new OpenSslServerContext(crtFile, keyFile, pass);
+- public final synchronized SSLEngineResult.HandshakeStatus getHandshakeStatus() {
+- // Check if we are in the initial handshake phase or shutdown phase
+- if (needPendingStatus()) {
+- if (needTask) {
+- // There is a task outstanding
+- return NEED_TASK;
+- }
+- return pendingStatus(SSL.bioLengthNonApplication(networkBIO));
+- }
+- return NOT_HANDSHAKING;
- }
--}
-diff --git a/handler/src/test/java/io/netty/handler/ssl/OpenSslTestUtils.java b/handler/src/test/java/io/netty/handler/ssl/OpenSslTestUtils.java
-deleted file mode 100644
-index 7882a61..0000000
---- a/handler/src/test/java/io/netty/handler/ssl/OpenSslTestUtils.java
-+++ /dev/null
-@@ -1,27 +0,0 @@
--/*
-- * Copyright 2017 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
-
--import static org.junit.Assume.assumeTrue;
--
--final class OpenSslTestUtils {
-- private OpenSslTestUtils() {
+- private SSLEngineResult.HandshakeStatus getHandshakeStatus(int pending) {
+- // Check if we are in the initial handshake phase or shutdown phase
+- if (needPendingStatus()) {
+- if (needTask) {
+- // There is a task outstanding
+- return NEED_TASK;
+- }
+- return pendingStatus(pending);
+- }
+- return NOT_HANDSHAKING;
- }
-
-- static void checkShouldUseKeyManagerFactory() {
-- assumeTrue(OpenSsl.supportsKeyManagerFactory() && OpenSsl.useKeyManagerFactory());
+- private boolean needPendingStatus() {
+- return handshakeState != HandshakeState.NOT_STARTED && !isDestroyed()
+- && (handshakeState != HandshakeState.FINISHED || isInboundDone() || isOutboundDone());
- }
--}
-diff --git a/handler/src/test/java/io/netty/handler/ssl/PemEncodedTest.java b/handler/src/test/java/io/netty/handler/ssl/PemEncodedTest.java
-deleted file mode 100644
-index 793f772..0000000
---- a/handler/src/test/java/io/netty/handler/ssl/PemEncodedTest.java
-+++ /dev/null
-@@ -1,95 +0,0 @@
--/*
-- * Copyright 2016 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
-
--package io.netty.handler.ssl;
+- /**
+- * Converts the specified OpenSSL cipher suite to the Java cipher suite.
+- */
+- private String toJavaCipherSuite(String openSslCipherSuite) {
+- if (openSslCipherSuite == null) {
+- return null;
+- }
-
--import static org.junit.Assert.assertEquals;
--import static org.junit.Assert.assertTrue;
--import static org.junit.Assume.assumeFalse;
--import static org.junit.Assume.assumeTrue;
+- String version = SSL.getVersion(ssl);
+- String prefix = toJavaCipherSuitePrefix(version);
+- return CipherSuiteConverter.toJava(openSslCipherSuite, prefix);
+- }
-
--import java.io.ByteArrayOutputStream;
--import java.io.File;
--import java.io.FileInputStream;
+- /**
+- * Converts the protocol version string returned by {@link SSL#getVersion(long)} to protocol family string.
+- */
+- private static String toJavaCipherSuitePrefix(String protocolVersion) {
+- final char c;
+- if (protocolVersion == null || protocolVersion.isEmpty()) {
+- c = 0;
+- } else {
+- c = protocolVersion.charAt(0);
+- }
-
--import org.junit.Test;
+- switch (c) {
+- case 'T':
+- return "TLS";
+- case 'S':
+- return "SSL";
+- default:
+- return "UNKNOWN";
+- }
+- }
-
--import io.netty.handler.ssl.util.SelfSignedCertificate;
--import io.netty.util.ReferenceCountUtil;
+- @Override
+- public final void setUseClientMode(boolean clientMode) {
+- if (clientMode != this.clientMode) {
+- throw new UnsupportedOperationException();
+- }
+- }
-
--public class PemEncodedTest {
+- @Override
+- public final boolean getUseClientMode() {
+- return clientMode;
+- }
-
-- @Test
-- public void testPemEncodedOpenSsl() throws Exception {
-- testPemEncoded(SslProvider.OPENSSL);
+- @Override
+- public final void setNeedClientAuth(boolean b) {
+- setClientAuth(b ? ClientAuth.REQUIRE : ClientAuth.NONE);
- }
-
-- @Test
-- public void testPemEncodedOpenSslRef() throws Exception {
-- testPemEncoded(SslProvider.OPENSSL_REFCNT);
+- @Override
+- public final boolean getNeedClientAuth() {
+- return clientAuth == ClientAuth.REQUIRE;
- }
-
-- private static void testPemEncoded(SslProvider provider) throws Exception {
-- assumeTrue(OpenSsl.isAvailable());
-- assumeFalse(OpenSsl.useKeyManagerFactory());
-- PemPrivateKey pemKey;
-- PemX509Certificate pemCert;
-- SelfSignedCertificate ssc = new SelfSignedCertificate();
-- try {
-- pemKey = PemPrivateKey.valueOf(toByteArray(ssc.privateKey()));
-- pemCert = PemX509Certificate.valueOf(toByteArray(ssc.certificate()));
-- } finally {
-- ssc.delete();
-- }
+- @Override
+- public final void setWantClientAuth(boolean b) {
+- setClientAuth(b ? ClientAuth.OPTIONAL : ClientAuth.NONE);
+- }
-
-- SslContext context = SslContextBuilder.forServer(pemKey, pemCert)
-- .sslProvider(provider)
-- .build();
-- assertEquals(1, pemKey.refCnt());
-- assertEquals(1, pemCert.refCnt());
-- try {
-- assertTrue(context instanceof ReferenceCountedOpenSslContext);
-- } finally {
-- ReferenceCountUtil.release(context);
-- assertRelease(pemKey);
-- assertRelease(pemCert);
-- }
+- @Override
+- public final boolean getWantClientAuth() {
+- return clientAuth == ClientAuth.OPTIONAL;
- }
-
-- private static void assertRelease(PemEncoded encoded) {
-- assertTrue(encoded.release());
+- /**
+- * See <a href="https://www.openssl.org/docs/man1.0.2/ssl/SSL_set_verify.html">SSL_set_verify</a> and
+- * {@link SSL#setVerify(long, int, int)}.
+- */
+- @UnstableApi
+- public final synchronized void setVerify(int verifyMode, int depth) {
+- if (!isDestroyed()) {
+- SSL.setVerify(ssl, verifyMode, depth);
+- }
- }
-
-- private static byte[] toByteArray(File file) throws Exception {
-- FileInputStream in = new FileInputStream(file);
-- try {
-- ByteArrayOutputStream baos = new ByteArrayOutputStream();
-- try {
-- byte[] buf = new byte[1024];
-- int len;
-- while ((len = in.read(buf)) != -1) {
-- baos.write(buf, 0, len);
+- private void setClientAuth(ClientAuth mode) {
+- if (clientMode) {
+- return;
+- }
+- synchronized (this) {
+- if (clientAuth == mode) {
+- // No need to issue any JNI calls if the mode is the same
+- return;
+- }
+- if (!isDestroyed()) {
+- switch (mode) {
+- case NONE:
+- SSL.setVerify(ssl, SSL.SSL_CVERIFY_NONE, ReferenceCountedOpenSslContext.VERIFY_DEPTH);
+- break;
+- case REQUIRE:
+- SSL.setVerify(ssl, SSL.SSL_CVERIFY_REQUIRED, ReferenceCountedOpenSslContext.VERIFY_DEPTH);
+- break;
+- case OPTIONAL:
+- SSL.setVerify(ssl, SSL.SSL_CVERIFY_OPTIONAL, ReferenceCountedOpenSslContext.VERIFY_DEPTH);
+- break;
+- default:
+- throw new Error(mode.toString());
- }
-- } finally {
-- baos.close();
- }
+- clientAuth = mode;
+- }
+- }
-
-- return baos.toByteArray();
-- } finally {
-- in.close();
+- @Override
+- public final void setEnableSessionCreation(boolean b) {
+- if (b) {
+- throw new UnsupportedOperationException();
- }
- }
--}
-diff --git a/handler/src/test/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngineTest.java b/handler/src/test/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngineTest.java
-deleted file mode 100644
-index 6d38940..0000000
---- a/handler/src/test/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngineTest.java
-+++ /dev/null
-@@ -1,57 +0,0 @@
--/*
-- * Copyright 2016 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
-
--import io.netty.util.ReferenceCountUtil;
+- @Override
+- public final boolean getEnableSessionCreation() {
+- return false;
+- }
-
--import javax.net.ssl.SSLEngine;
+- @SuppressJava6Requirement(reason = "Usage guarded by java version check")
+- @Override
+- public final synchronized SSLParameters getSSLParameters() {
+- SSLParameters sslParameters = super.getSSLParameters();
+-
+- int version = PlatformDependent.javaVersion();
+- if (version >= 7) {
+- sslParameters.setEndpointIdentificationAlgorithm(endPointIdentificationAlgorithm);
+- Java7SslParametersUtils.setAlgorithmConstraints(sslParameters, algorithmConstraints);
+- if (version >= 8) {
+- if (sniHostNames != null) {
+- Java8SslUtils.setSniHostNames(sslParameters, sniHostNames);
+- }
+- if (!isDestroyed()) {
+- Java8SslUtils.setUseCipherSuitesOrder(
+- sslParameters, (SSL.getOptions(ssl) & SSL.SSL_OP_CIPHER_SERVER_PREFERENCE) != 0);
+- }
+-
+- Java8SslUtils.setSNIMatchers(sslParameters, matchers);
+- }
+- }
+- return sslParameters;
+- }
-
--public class ReferenceCountedOpenSslEngineTest extends OpenSslEngineTest {
+- @SuppressJava6Requirement(reason = "Usage guarded by java version check")
+- @Override
+- public final synchronized void setSSLParameters(SSLParameters sslParameters) {
+- int version = PlatformDependent.javaVersion();
+- if (version >= 7) {
+- if (sslParameters.getAlgorithmConstraints() != null) {
+- throw new IllegalArgumentException("AlgorithmConstraints are not supported.");
+- }
-
-- public ReferenceCountedOpenSslEngineTest(BufferType type) {
-- super(type);
-- }
+- boolean isDestroyed = isDestroyed();
+- if (version >= 8) {
+- if (!isDestroyed) {
+- if (clientMode) {
+- final List<String> sniHostNames = Java8SslUtils.getSniHostNames(sslParameters);
+- for (String name: sniHostNames) {
+- SSL.setTlsExtHostName(ssl, name);
+- }
+- this.sniHostNames = sniHostNames;
+- }
+- if (Java8SslUtils.getUseCipherSuitesOrder(sslParameters)) {
+- SSL.setOptions(ssl, SSL.SSL_OP_CIPHER_SERVER_PREFERENCE);
+- } else {
+- SSL.clearOptions(ssl, SSL.SSL_OP_CIPHER_SERVER_PREFERENCE);
+- }
+- }
+- matchers = sslParameters.getSNIMatchers();
+- }
-
-- @Override
-- protected SslProvider sslClientProvider() {
-- return SslProvider.OPENSSL_REFCNT;
+- final String endPointIdentificationAlgorithm = sslParameters.getEndpointIdentificationAlgorithm();
+- if (!isDestroyed) {
+- // If the user asks for hostname verification we must ensure we verify the peer.
+- // If the user disables hostname verification we leave it up to the user to change the mode manually.
+- if (clientMode && isEndPointVerificationEnabled(endPointIdentificationAlgorithm)) {
+- SSL.setVerify(ssl, SSL.SSL_CVERIFY_REQUIRED, -1);
+- }
+- }
+- this.endPointIdentificationAlgorithm = endPointIdentificationAlgorithm;
+- algorithmConstraints = sslParameters.getAlgorithmConstraints();
+- }
+- super.setSSLParameters(sslParameters);
- }
-
-- @Override
-- protected SslProvider sslServerProvider() {
-- return SslProvider.OPENSSL_REFCNT;
+- private static boolean isEndPointVerificationEnabled(String endPointIdentificationAlgorithm) {
+- return endPointIdentificationAlgorithm != null && !endPointIdentificationAlgorithm.isEmpty();
- }
-
-- @Override
-- protected void cleanupClientSslContext(SslContext ctx) {
-- ReferenceCountUtil.release(ctx);
+- private boolean isDestroyed() {
+- return destroyed;
- }
-
-- @Override
-- protected void cleanupClientSslEngine(SSLEngine engine) {
-- ReferenceCountUtil.release(engine);
+- final boolean checkSniHostnameMatch(byte[] hostname) {
+- return Java8SslUtils.checkSniHostnameMatch(matchers, hostname);
- }
-
- @Override
-- protected void cleanupServerSslContext(SslContext ctx) {
-- ReferenceCountUtil.release(ctx);
+- public String getNegotiatedApplicationProtocol() {
+- return applicationProtocol;
- }
-
-- @Override
-- protected void cleanupServerSslEngine(SSLEngine engine) {
-- ReferenceCountUtil.release(engine);
+- private static long bufferAddress(ByteBuffer b) {
+- assert b.isDirect();
+- if (PlatformDependent.hasUnsafe()) {
+- return PlatformDependent.directBufferAddress(b);
+- }
+- return Buffer.address(b);
- }
--}
-diff --git a/handler/src/test/java/io/netty/handler/ssl/SniClientTest.java b/handler/src/test/java/io/netty/handler/ssl/SniClientTest.java
-deleted file mode 100644
-index 3193d20..0000000
---- a/handler/src/test/java/io/netty/handler/ssl/SniClientTest.java
-+++ /dev/null
-@@ -1,161 +0,0 @@
--/*
-- * Copyright 2016 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
--
--import io.netty.bootstrap.Bootstrap;
--import io.netty.bootstrap.ServerBootstrap;
--import io.netty.buffer.ByteBufAllocator;
--import io.netty.channel.Channel;
--import io.netty.channel.ChannelInitializer;
--import io.netty.channel.DefaultEventLoopGroup;
--import io.netty.channel.EventLoopGroup;
--import io.netty.channel.local.LocalAddress;
--import io.netty.channel.local.LocalChannel;
--import io.netty.channel.local.LocalServerChannel;
--import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
--import io.netty.handler.ssl.util.SelfSignedCertificate;
--import io.netty.util.Mapping;
--import io.netty.util.concurrent.Promise;
--import io.netty.util.internal.PlatformDependent;
--import org.junit.Assert;
--import org.junit.Assume;
--import org.junit.Test;
-
--import java.nio.channels.ClosedChannelException;
--
--public class SniClientTest {
--
-- @Test(timeout = 30000)
-- public void testSniClientJdkSslServerJdkSsl() throws Exception {
-- testSniClient(SslProvider.JDK, SslProvider.JDK);
-- }
+- private final class DefaultOpenSslSession implements OpenSslSession {
+- private final OpenSslSessionContext sessionContext;
-
-- @Test(timeout = 30000)
-- public void testSniClientOpenSslServerOpenSsl() throws Exception {
-- Assume.assumeTrue(OpenSsl.isAvailable());
-- testSniClient(SslProvider.OPENSSL, SslProvider.OPENSSL);
-- }
+- // These are guarded by synchronized(OpenSslEngine.this) as handshakeFinished() may be triggered by any
+- // thread.
+- private X509Certificate[] x509PeerCerts;
+- private Certificate[] peerCerts;
-
-- @Test(timeout = 30000)
-- public void testSniClientJdkSslServerOpenSsl() throws Exception {
-- Assume.assumeTrue(OpenSsl.isAvailable());
-- testSniClient(SslProvider.JDK, SslProvider.OPENSSL);
-- }
+- private String protocol;
+- private String cipher;
+- private byte[] id;
+- private long creationTime;
+- private volatile int applicationBufferSize = MAX_PLAINTEXT_LENGTH;
-
-- @Test(timeout = 30000)
-- public void testSniClientOpenSslServerJdkSsl() throws Exception {
-- Assume.assumeTrue(OpenSsl.isAvailable());
-- testSniClient(SslProvider.OPENSSL, SslProvider.JDK);
-- }
+- // lazy init for memory reasons
+- private Map<String, Object> values;
-
-- @Test(timeout = 30000)
-- public void testSniSNIMatcherMatchesClientJdkSslServerJdkSsl() throws Exception {
-- Assume.assumeTrue(PlatformDependent.javaVersion() >= 8);
-- SniClientJava8TestUtil.testSniClient(SslProvider.JDK, SslProvider.JDK, true);
-- }
+- DefaultOpenSslSession(OpenSslSessionContext sessionContext) {
+- this.sessionContext = sessionContext;
+- }
-
-- @Test(timeout = 30000, expected = ClosedChannelException.class)
-- public void testSniSNIMatcherDoesNotMatchClientJdkSslServerJdkSsl() throws Exception {
-- Assume.assumeTrue(PlatformDependent.javaVersion() >= 8);
-- SniClientJava8TestUtil.testSniClient(SslProvider.JDK, SslProvider.JDK, false);
-- }
+- private SSLSessionBindingEvent newSSLSessionBindingEvent(String name) {
+- return new SSLSessionBindingEvent(session, name);
+- }
-
-- @Test(timeout = 30000)
-- public void testSniSNIMatcherMatchesClientOpenSslServerOpenSsl() throws Exception {
-- Assume.assumeTrue(PlatformDependent.javaVersion() >= 8);
-- Assume.assumeTrue(OpenSsl.isAvailable());
-- SniClientJava8TestUtil.testSniClient(SslProvider.OPENSSL, SslProvider.OPENSSL, true);
-- }
+- @Override
+- public byte[] getId() {
+- synchronized (ReferenceCountedOpenSslEngine.this) {
+- if (id == null) {
+- return EmptyArrays.EMPTY_BYTES;
+- }
+- return id.clone();
+- }
+- }
-
-- @Test(timeout = 30000, expected = ClosedChannelException.class)
-- public void testSniSNIMatcherDoesNotMatchClientOpenSslServerOpenSsl() throws Exception {
-- Assume.assumeTrue(PlatformDependent.javaVersion() >= 8);
-- Assume.assumeTrue(OpenSsl.isAvailable());
-- SniClientJava8TestUtil.testSniClient(SslProvider.OPENSSL, SslProvider.OPENSSL, false);
-- }
+- @Override
+- public SSLSessionContext getSessionContext() {
+- return sessionContext;
+- }
-
-- @Test(timeout = 30000)
-- public void testSniSNIMatcherMatchesClientJdkSslServerOpenSsl() throws Exception {
-- Assume.assumeTrue(PlatformDependent.javaVersion() >= 8);
-- Assume.assumeTrue(OpenSsl.isAvailable());
-- SniClientJava8TestUtil.testSniClient(SslProvider.JDK, SslProvider.OPENSSL, true);
-- }
+- @Override
+- public long getCreationTime() {
+- synchronized (ReferenceCountedOpenSslEngine.this) {
+- if (creationTime == 0 && !isDestroyed()) {
+- creationTime = SSL.getTime(ssl) * 1000L;
+- }
+- }
+- return creationTime;
+- }
-
-- @Test(timeout = 30000, expected = ClosedChannelException.class)
-- public void testSniSNIMatcherDoesNotMatchClientJdkSslServerOpenSsl() throws Exception {
-- Assume.assumeTrue(PlatformDependent.javaVersion() >= 8);
-- Assume.assumeTrue(OpenSsl.isAvailable());
-- SniClientJava8TestUtil.testSniClient(SslProvider.JDK, SslProvider.OPENSSL, false);
-- }
+- @Override
+- public long getLastAccessedTime() {
+- long lastAccessed = ReferenceCountedOpenSslEngine.this.lastAccessed;
+- // if lastAccessed is -1 we will just return the creation time as the handshake was not started yet.
+- return lastAccessed == -1 ? getCreationTime() : lastAccessed;
+- }
-
-- @Test(timeout = 30000)
-- public void testSniSNIMatcherMatchesClientOpenSslServerJdkSsl() throws Exception {
-- Assume.assumeTrue(PlatformDependent.javaVersion() >= 8);
-- Assume.assumeTrue(OpenSsl.isAvailable());
-- SniClientJava8TestUtil.testSniClient(SslProvider.OPENSSL, SslProvider.JDK, true);
-- }
+- @Override
+- public void invalidate() {
+- synchronized (ReferenceCountedOpenSslEngine.this) {
+- if (!isDestroyed()) {
+- SSL.setTimeout(ssl, 0);
+- }
+- }
+- }
-
-- @Test(timeout = 30000, expected = ClosedChannelException.class)
-- public void testSniSNIMatcherDoesNotMatchClientOpenSslServerJdkSsl() throws Exception {
-- Assume.assumeTrue(PlatformDependent.javaVersion() >= 8);
-- Assume.assumeTrue(OpenSsl.isAvailable());
-- SniClientJava8TestUtil.testSniClient(SslProvider.OPENSSL, SslProvider.JDK, false);
-- }
+- @Override
+- public boolean isValid() {
+- synchronized (ReferenceCountedOpenSslEngine.this) {
+- if (!isDestroyed()) {
+- return System.currentTimeMillis() - (SSL.getTimeout(ssl) * 1000L) < (SSL.getTime(ssl) * 1000L);
+- }
+- }
+- return false;
+- }
-
-- private static void testSniClient(SslProvider sslClientProvider, SslProvider sslServerProvider) throws Exception {
-- final String sniHost = "sni.netty.io";
-- LocalAddress address = new LocalAddress("test");
-- EventLoopGroup group = new DefaultEventLoopGroup(1);
-- Channel sc = null;
-- Channel cc = null;
-- try {
-- SelfSignedCertificate cert = new SelfSignedCertificate();
-- final SslContext sslServerContext = SslContextBuilder.forServer(cert.key(), cert.cert())
-- .sslProvider(sslServerProvider).build();
+- @Override
+- public void putValue(String name, Object value) {
+- ObjectUtil.checkNotNull(name, "name");
+- ObjectUtil.checkNotNull(value, "value");
-
-- final Promise<String> promise = group.next().newPromise();
-- ServerBootstrap sb = new ServerBootstrap();
-- sc = sb.group(group).channel(LocalServerChannel.class).childHandler(new ChannelInitializer<Channel>() {
-- @Override
-- protected void initChannel(Channel ch) throws Exception {
-- ch.pipeline().addFirst(new SniHandler(new Mapping<String, SslContext>() {
-- @Override
-- public SslContext map(String input) {
-- promise.setSuccess(input);
-- return sslServerContext;
-- }
-- }));
+- final Object old;
+- synchronized (this) {
+- Map<String, Object> values = this.values;
+- if (values == null) {
+- // Use size of 2 to keep the memory overhead small
+- values = this.values = new HashMap<String, Object>(2);
- }
-- }).bind(address).syncUninterruptibly().channel();
--
-- SslContext sslContext = SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE)
-- .sslProvider(sslClientProvider).build();
-- Bootstrap cb = new Bootstrap();
-- cc = cb.group(group).channel(LocalChannel.class).handler(new SslHandler(
-- sslContext.newEngine(ByteBufAllocator.DEFAULT, sniHost, -1)))
-- .connect(address).syncUninterruptibly().channel();
-- Assert.assertEquals(sniHost, promise.syncUninterruptibly().getNow());
-- } finally {
-- if (cc != null) {
-- cc.close().syncUninterruptibly();
+- old = values.put(name, value);
- }
-- if (sc != null) {
-- sc.close().syncUninterruptibly();
+-
+- if (value instanceof SSLSessionBindingListener) {
+- // Use newSSLSessionBindingEvent so we alway use the wrapper if needed.
+- ((SSLSessionBindingListener) value).valueBound(newSSLSessionBindingEvent(name));
- }
-- group.shutdownGracefully();
+- notifyUnbound(old, name);
- }
-- }
--}
-diff --git a/handler/src/test/java/io/netty/handler/ssl/SniHandlerTest.java b/handler/src/test/java/io/netty/handler/ssl/SniHandlerTest.java
-deleted file mode 100644
-index 07c87c6..0000000
---- a/handler/src/test/java/io/netty/handler/ssl/SniHandlerTest.java
-+++ /dev/null
-@@ -1,496 +0,0 @@
--/*
-- * Copyright 2014 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
-
--package io.netty.handler.ssl;
+- @Override
+- public Object getValue(String name) {
+- ObjectUtil.checkNotNull(name, "name");
+- synchronized (this) {
+- if (values == null) {
+- return null;
+- }
+- return values.get(name);
+- }
+- }
-
--import static org.hamcrest.CoreMatchers.is;
--import static org.hamcrest.CoreMatchers.nullValue;
--import static org.junit.Assert.assertEquals;
--import static org.junit.Assert.assertThat;
--import static org.junit.Assert.assertTrue;
--import static org.junit.Assume.assumeTrue;
+- @Override
+- public void removeValue(String name) {
+- ObjectUtil.checkNotNull(name, "name");
-
--import java.io.File;
--import java.net.InetSocketAddress;
--import java.util.ArrayList;
--import java.util.List;
--import java.util.concurrent.CountDownLatch;
--import java.util.concurrent.TimeUnit;
+- final Object old;
+- synchronized (this) {
+- Map<String, Object> values = this.values;
+- if (values == null) {
+- return;
+- }
+- old = values.remove(name);
+- }
-
--import javax.net.ssl.SSLEngine;
+- notifyUnbound(old, name);
+- }
-
--import org.junit.Test;
+- @Override
+- public String[] getValueNames() {
+- synchronized (this) {
+- Map<String, Object> values = this.values;
+- if (values == null || values.isEmpty()) {
+- return EmptyArrays.EMPTY_STRINGS;
+- }
+- return values.keySet().toArray(new String[0]);
+- }
+- }
-
--import io.netty.bootstrap.Bootstrap;
--import io.netty.bootstrap.ServerBootstrap;
--import io.netty.buffer.ByteBufAllocator;
--import io.netty.buffer.Unpooled;
--import io.netty.channel.Channel;
--import io.netty.channel.ChannelFuture;
--import io.netty.channel.ChannelHandlerContext;
--import io.netty.channel.ChannelInitializer;
--import io.netty.channel.ChannelPipeline;
--import io.netty.channel.DefaultEventLoopGroup;
--import io.netty.channel.EventLoopGroup;
--import io.netty.channel.embedded.EmbeddedChannel;
--import io.netty.channel.local.LocalAddress;
--import io.netty.channel.local.LocalChannel;
--import io.netty.channel.local.LocalServerChannel;
--import io.netty.channel.nio.NioEventLoopGroup;
--import io.netty.channel.socket.nio.NioServerSocketChannel;
--import io.netty.channel.socket.nio.NioSocketChannel;
--import io.netty.handler.codec.DecoderException;
--import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
--import io.netty.handler.ssl.util.SelfSignedCertificate;
--import io.netty.util.DomainNameMapping;
--import io.netty.util.DomainNameMappingBuilder;
--import io.netty.util.Mapping;
--import io.netty.util.ReferenceCountUtil;
--import io.netty.util.ReferenceCounted;
--import io.netty.util.concurrent.Promise;
--import io.netty.util.internal.ObjectUtil;
--import io.netty.util.internal.StringUtil;
--import org.junit.runner.RunWith;
--import org.junit.runners.Parameterized;
+- private void notifyUnbound(Object value, String name) {
+- if (value instanceof SSLSessionBindingListener) {
+- // Use newSSLSessionBindingEvent so we alway use the wrapper if needed.
+- ((SSLSessionBindingListener) value).valueUnbound(newSSLSessionBindingEvent(name));
+- }
+- }
-
--(a)RunWith(Parameterized.class)
--public class SniHandlerTest {
+- /**
+- * Finish the handshake and so init everything in the {@link OpenSslSession} that should be accessible by
+- * the user.
+- */
+- @Override
+- public void handshakeFinished() throws SSLException {
+- synchronized (ReferenceCountedOpenSslEngine.this) {
+- if (!isDestroyed()) {
+- id = SSL.getSessionId(ssl);
+- cipher = toJavaCipherSuite(SSL.getCipherForSSL(ssl));
+- protocol = SSL.getVersion(ssl);
-
-- private static ApplicationProtocolConfig newApnConfig() {
-- return new ApplicationProtocolConfig(
-- ApplicationProtocolConfig.Protocol.ALPN,
-- // NO_ADVERTISE is currently the only mode supported by both OpenSsl and JDK providers.
-- ApplicationProtocolConfig.SelectorFailureBehavior.NO_ADVERTISE,
-- // ACCEPT is currently the only mode supported by both OpenSsl and JDK providers.
-- ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT,
-- "myprotocol");
-- }
+- initPeerCerts();
+- selectApplicationProtocol();
+- calculateMaxWrapOverhead();
-
-- private static void assumeApnSupported(SslProvider provider) {
-- switch (provider) {
-- case OPENSSL:
-- case OPENSSL_REFCNT:
-- assumeTrue(OpenSsl.isAlpnSupported());
-- break;
-- case JDK:
-- assumeTrue(JettyAlpnSslEngine.isAvailable());
-- break;
-- default:
-- throw new Error();
+- handshakeState = HandshakeState.FINISHED;
+- } else {
+- throw new SSLException("Already closed");
+- }
+- }
- }
-- }
-
-- private static SslContext makeSslContext(SslProvider provider, boolean apn) throws Exception {
-- if (apn) {
-- assumeApnSupported(provider);
+- /**
+- * Init peer certificates that can be obtained via {@link #getPeerCertificateChain()}
+- * and {@link #getPeerCertificates()}.
+- */
+- private void initPeerCerts() {
+- // Return the full chain from the JNI layer.
+- byte[][] chain = SSL.getPeerCertChain(ssl);
+- if (clientMode) {
+- if (isEmpty(chain)) {
+- peerCerts = EmptyArrays.EMPTY_CERTIFICATES;
+- x509PeerCerts = EmptyArrays.EMPTY_JAVAX_X509_CERTIFICATES;
+- } else {
+- peerCerts = new Certificate[chain.length];
+- x509PeerCerts = new X509Certificate[chain.length];
+- initCerts(chain, 0);
+- }
+- } else {
+- // if used on the server side SSL_get_peer_cert_chain(...) will not include the remote peer
+- // certificate. We use SSL_get_peer_certificate to get it in this case and add it to our
+- // array later.
+- //
+- // See https://www.openssl.org/docs/ssl/SSL_get_peer_cert_chain.html
+- byte[] clientCert = SSL.getPeerCertificate(ssl);
+- if (isEmpty(clientCert)) {
+- peerCerts = EmptyArrays.EMPTY_CERTIFICATES;
+- x509PeerCerts = EmptyArrays.EMPTY_JAVAX_X509_CERTIFICATES;
+- } else {
+- if (isEmpty(chain)) {
+- peerCerts = new Certificate[] {new OpenSslX509Certificate(clientCert)};
+- x509PeerCerts = new X509Certificate[] {new OpenSslJavaxX509Certificate(clientCert)};
+- } else {
+- peerCerts = new Certificate[chain.length + 1];
+- x509PeerCerts = new X509Certificate[chain.length + 1];
+- peerCerts[0] = new OpenSslX509Certificate(clientCert);
+- x509PeerCerts[0] = new OpenSslJavaxX509Certificate(clientCert);
+- initCerts(chain, 1);
+- }
+- }
+- }
- }
-
-- File keyFile = new File(SniHandlerTest.class.getResource("test_encrypted.pem").getFile());
-- File crtFile = new File(SniHandlerTest.class.getResource("test.crt").getFile());
--
-- SslContextBuilder sslCtxBuilder = SslContextBuilder.forServer(crtFile, keyFile, "12345")
-- .sslProvider(provider);
-- if (apn) {
-- sslCtxBuilder.applicationProtocolConfig(newApnConfig());
+- private void initCerts(byte[][] chain, int startPos) {
+- for (int i = 0; i < chain.length; i++) {
+- int certPos = startPos + i;
+- peerCerts[certPos] = new OpenSslX509Certificate(chain[i]);
+- x509PeerCerts[certPos] = new OpenSslJavaxX509Certificate(chain[i]);
+- }
- }
-- return sslCtxBuilder.build();
-- }
-
-- private static SslContext makeSslClientContext(SslProvider provider, boolean apn) throws Exception {
-- if (apn) {
-- assumeApnSupported(provider);
+- /**
+- * Select the application protocol used.
+- */
+- private void selectApplicationProtocol() throws SSLException {
+- ApplicationProtocolConfig.SelectedListenerFailureBehavior behavior = apn.selectedListenerFailureBehavior();
+- List<String> protocols = apn.protocols();
+- String applicationProtocol;
+- switch (apn.protocol()) {
+- case NONE:
+- break;
+- // We always need to check for applicationProtocol == null as the remote peer may not support
+- // the TLS extension or may have returned an empty selection.
+- case ALPN:
+- applicationProtocol = SSL.getAlpnSelected(ssl);
+- if (applicationProtocol != null) {
+- ReferenceCountedOpenSslEngine.this.applicationProtocol = selectApplicationProtocol(
+- protocols, behavior, applicationProtocol);
+- }
+- break;
+- case NPN:
+- applicationProtocol = SSL.getNextProtoNegotiated(ssl);
+- if (applicationProtocol != null) {
+- ReferenceCountedOpenSslEngine.this.applicationProtocol = selectApplicationProtocol(
+- protocols, behavior, applicationProtocol);
+- }
+- break;
+- case NPN_AND_ALPN:
+- applicationProtocol = SSL.getAlpnSelected(ssl);
+- if (applicationProtocol == null) {
+- applicationProtocol = SSL.getNextProtoNegotiated(ssl);
+- }
+- if (applicationProtocol != null) {
+- ReferenceCountedOpenSslEngine.this.applicationProtocol = selectApplicationProtocol(
+- protocols, behavior, applicationProtocol);
+- }
+- break;
+- default:
+- throw new Error();
+- }
- }
-
-- File crtFile = new File(SniHandlerTest.class.getResource("test.crt").getFile());
--
-- SslContextBuilder sslCtxBuilder = SslContextBuilder.forClient().trustManager(crtFile).sslProvider(provider);
-- if (apn) {
-- sslCtxBuilder.applicationProtocolConfig(newApnConfig());
+- private String selectApplicationProtocol(List<String> protocols,
+- ApplicationProtocolConfig.SelectedListenerFailureBehavior behavior,
+- String applicationProtocol) throws SSLException {
+- if (behavior == ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT) {
+- return applicationProtocol;
+- } else {
+- int size = protocols.size();
+- assert size > 0;
+- if (protocols.contains(applicationProtocol)) {
+- return applicationProtocol;
+- } else {
+- if (behavior == ApplicationProtocolConfig.SelectedListenerFailureBehavior.CHOOSE_MY_LAST_PROTOCOL) {
+- return protocols.get(size - 1);
+- } else {
+- throw new SSLException("unknown protocol " + applicationProtocol);
+- }
+- }
+- }
- }
-- return sslCtxBuilder.build();
-- }
-
-- @Parameterized.Parameters(name = "{index}: sslProvider={0}")
-- public static Iterable<?> data() {
-- List<SslProvider> params = new ArrayList<SslProvider>(3);
-- if (OpenSsl.isAvailable()) {
-- params.add(SslProvider.OPENSSL);
-- params.add(SslProvider.OPENSSL_REFCNT);
+- @Override
+- public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException {
+- synchronized (ReferenceCountedOpenSslEngine.this) {
+- if (isEmpty(peerCerts)) {
+- throw new SSLPeerUnverifiedException("peer not verified");
+- }
+- return peerCerts.clone();
+- }
- }
-- params.add(SslProvider.JDK);
-- return params;
-- }
--
-- private final SslProvider provider;
-
-- public SniHandlerTest(SslProvider provider) {
-- this.provider = provider;
-- }
--
-- @Test
-- public void testServerNameParsing() throws Exception {
-- SslContext nettyContext = makeSslContext(provider, false);
-- SslContext leanContext = makeSslContext(provider, false);
-- SslContext leanContext2 = makeSslContext(provider, false);
--
-- try {
-- DomainNameMapping<SslContext> mapping = new DomainNameMappingBuilder<SslContext>(nettyContext)
-- .add("*.netty.io", nettyContext)
-- // input with custom cases
-- .add("*.LEANCLOUD.CN", leanContext)
-- // a hostname conflict with previous one, since we are using order-sensitive config,
-- // the engine won't be used with the handler.
-- .add("chat4.leancloud.cn", leanContext2)
-- .build();
--
-- SniHandler handler = new SniHandler(mapping);
-- EmbeddedChannel ch = new EmbeddedChannel(handler);
--
-- try {
-- // hex dump of a client hello packet, which contains hostname "CHAT4.LEANCLOUD.CN"
-- String tlsHandshakeMessageHex1 = "16030100";
-- // part 2
-- String tlsHandshakeMessageHex = "c6010000c20303bb0855d66532c05a0ef784f7c384feeafa68b3" +
-- "b655ac7288650d5eed4aa3fb52000038c02cc030009fcca9cca8ccaac02b" +
-- "c02f009ec024c028006bc023c0270067c00ac0140039c009c0130033009d" +
-- "009c003d003c0035002f00ff010000610000001700150000124348415434" +
-- "2e4c45414e434c4f55442e434e000b000403000102000a000a0008001d00" +
-- "170019001800230000000d0020001e060106020603050105020503040104" +
-- "0204030301030203030201020202030016000000170000";
--
-- ch.writeInbound(Unpooled.wrappedBuffer(StringUtil.decodeHexDump(tlsHandshakeMessageHex1)));
-- ch.writeInbound(Unpooled.wrappedBuffer(StringUtil.decodeHexDump(tlsHandshakeMessageHex)));
--
-- // This should produce an alert
-- assertTrue(ch.finish());
--
-- assertThat(handler.hostname(), is("chat4.leancloud.cn"));
-- assertThat(handler.sslContext(), is(leanContext));
-- } finally {
-- ch.finishAndReleaseAll();
+- @Override
+- public Certificate[] getLocalCertificates() {
+- Certificate[] localCerts = ReferenceCountedOpenSslEngine.this.localCertificateChain;
+- if (localCerts == null) {
+- return null;
- }
-- } finally {
-- releaseAll(leanContext, leanContext2, nettyContext);
+- return localCerts.clone();
- }
-- }
--
-- @Test(expected = DecoderException.class)
-- public void testNonAsciiServerNameParsing() throws Exception {
-- SslContext nettyContext = makeSslContext(provider, false);
-- SslContext leanContext = makeSslContext(provider, false);
-- SslContext leanContext2 = makeSslContext(provider, false);
-
-- try {
-- DomainNameMapping<SslContext> mapping = new DomainNameMappingBuilder<SslContext>(nettyContext)
-- .add("*.netty.io", nettyContext)
-- // input with custom cases
-- .add("*.LEANCLOUD.CN", leanContext)
-- // a hostname conflict with previous one, since we are using order-sensitive config,
-- // the engine won't be used with the handler.
-- .add("chat4.leancloud.cn", leanContext2)
-- .build();
--
-- SniHandler handler = new SniHandler(mapping);
-- EmbeddedChannel ch = new EmbeddedChannel(handler);
--
-- try {
-- // hex dump of a client hello packet, which contains an invalid hostname "CHAT4。LEANCLOUD。CN"
-- String tlsHandshakeMessageHex1 = "16030100";
-- // part 2
-- String tlsHandshakeMessageHex = "bd010000b90303a74225676d1814ba57faff3b366" +
-- "3656ed05ee9dbb2a4dbb1bb1c32d2ea5fc39e0000000100008c0000001700150000164348" +
-- "415434E380824C45414E434C4F5544E38082434E000b000403000102000a00340032000e0" +
-- "00d0019000b000c00180009000a0016001700080006000700140015000400050012001300" +
-- "0100020003000f0010001100230000000d0020001e0601060206030501050205030401040" +
-- "20403030103020303020102020203000f00010133740000";
--
-- // Push the handshake message.
-- // Decode should fail because of the badly encoded "HostName" string in the SNI extension
-- // that isn't ASCII as per RFC 6066 - https://tools.ietf.org/html/rfc6066#page-6
-- ch.writeInbound(Unpooled.wrappedBuffer(StringUtil.decodeHexDump(tlsHandshakeMessageHex1)));
-- ch.writeInbound(Unpooled.wrappedBuffer(StringUtil.decodeHexDump(tlsHandshakeMessageHex)));
-- } finally {
-- ch.finishAndReleaseAll();
+- @Override
+- public X509Certificate[] getPeerCertificateChain() throws SSLPeerUnverifiedException {
+- synchronized (ReferenceCountedOpenSslEngine.this) {
+- if (isEmpty(x509PeerCerts)) {
+- throw new SSLPeerUnverifiedException("peer not verified");
+- }
+- return x509PeerCerts.clone();
- }
-- } finally {
-- releaseAll(leanContext, leanContext2, nettyContext);
- }
-- }
--
-- @Test
-- public void testFallbackToDefaultContext() throws Exception {
-- SslContext nettyContext = makeSslContext(provider, false);
-- SslContext leanContext = makeSslContext(provider, false);
-- SslContext leanContext2 = makeSslContext(provider, false);
--
-- try {
-- DomainNameMapping<SslContext> mapping = new DomainNameMappingBuilder<SslContext>(nettyContext)
-- .add("*.netty.io", nettyContext)
-- // input with custom cases
-- .add("*.LEANCLOUD.CN", leanContext)
-- // a hostname conflict with previous one, since we are using order-sensitive config,
-- // the engine won't be used with the handler.
-- .add("chat4.leancloud.cn", leanContext2)
-- .build();
-
-- SniHandler handler = new SniHandler(mapping);
-- EmbeddedChannel ch = new EmbeddedChannel(handler);
--
-- // invalid
-- byte[] message = {22, 3, 1, 0, 0};
+- @Override
+- public Principal getPeerPrincipal() throws SSLPeerUnverifiedException {
+- Certificate[] peer = getPeerCertificates();
+- // No need for null or length > 0 is needed as this is done in getPeerCertificates()
+- // already.
+- return ((java.security.cert.X509Certificate) peer[0]).getSubjectX500Principal();
+- }
-
-- try {
-- // Push the handshake message.
-- ch.writeInbound(Unpooled.wrappedBuffer(message));
-- } catch (Exception e) {
-- // expected
+- @Override
+- public Principal getLocalPrincipal() {
+- Certificate[] local = ReferenceCountedOpenSslEngine.this.localCertificateChain;
+- if (local == null || local.length == 0) {
+- return null;
- }
--
-- assertThat(ch.finish(), is(false));
-- assertThat(handler.hostname(), nullValue());
-- assertThat(handler.sslContext(), is(nettyContext));
-- } finally {
-- releaseAll(leanContext, leanContext2, nettyContext);
+- return ((java.security.cert.X509Certificate) local[0]).getIssuerX500Principal();
- }
-- }
--
-- @Test
-- public void testSniWithApnHandler() throws Exception {
-- SslContext nettyContext = makeSslContext(provider, true);
-- SslContext sniContext = makeSslContext(provider, true);
-- final SslContext clientContext = makeSslClientContext(provider, true);
-- try {
-- final CountDownLatch serverApnDoneLatch = new CountDownLatch(1);
-- final CountDownLatch clientApnDoneLatch = new CountDownLatch(1);
--
-- final DomainNameMapping<SslContext> mapping = new DomainNameMappingBuilder<SslContext>(nettyContext)
-- .add("*.netty.io", nettyContext)
-- .add("sni.fake.site", sniContext).build();
-- final SniHandler handler = new SniHandler(mapping);
-- EventLoopGroup group = new NioEventLoopGroup(2);
-- Channel serverChannel = null;
-- Channel clientChannel = null;
-- try {
-- ServerBootstrap sb = new ServerBootstrap();
-- sb.group(group);
-- sb.channel(NioServerSocketChannel.class);
-- sb.childHandler(new ChannelInitializer<Channel>() {
-- @Override
-- protected void initChannel(Channel ch) throws Exception {
-- ChannelPipeline p = ch.pipeline();
-- // Server side SNI.
-- p.addLast(handler);
-- // Catch the notification event that APN has completed successfully.
-- p.addLast(new ApplicationProtocolNegotiationHandler("foo") {
-- @Override
-- protected void configurePipeline(ChannelHandlerContext ctx, String protocol) {
-- serverApnDoneLatch.countDown();
-- }
-- });
-- }
-- });
--
-- Bootstrap cb = new Bootstrap();
-- cb.group(group);
-- cb.channel(NioSocketChannel.class);
-- cb.handler(new ChannelInitializer<Channel>() {
-- @Override
-- protected void initChannel(Channel ch) throws Exception {
-- ch.pipeline().addLast(new SslHandler(clientContext.newEngine(
-- ch.alloc(), "sni.fake.site", -1)));
-- // Catch the notification event that APN has completed successfully.
-- ch.pipeline().addLast(new ApplicationProtocolNegotiationHandler("foo") {
-- @Override
-- protected void configurePipeline(ChannelHandlerContext ctx, String protocol) {
-- clientApnDoneLatch.countDown();
-- }
-- });
-- }
-- });
--
-- serverChannel = sb.bind(new InetSocketAddress(0)).sync().channel();
-
-- ChannelFuture ccf = cb.connect(serverChannel.localAddress());
-- assertTrue(ccf.awaitUninterruptibly().isSuccess());
-- clientChannel = ccf.channel();
--
-- assertTrue(serverApnDoneLatch.await(5, TimeUnit.SECONDS));
-- assertTrue(clientApnDoneLatch.await(5, TimeUnit.SECONDS));
-- assertThat(handler.hostname(), is("sni.fake.site"));
-- assertThat(handler.sslContext(), is(sniContext));
-- } finally {
-- if (serverChannel != null) {
-- serverChannel.close().sync();
-- }
-- if (clientChannel != null) {
-- clientChannel.close().sync();
+- @Override
+- public String getCipherSuite() {
+- synchronized (ReferenceCountedOpenSslEngine.this) {
+- if (cipher == null) {
+- return SslUtils.INVALID_CIPHER;
- }
-- group.shutdownGracefully(0, 0, TimeUnit.MICROSECONDS);
+- return cipher;
- }
-- } finally {
-- releaseAll(clientContext, nettyContext, sniContext);
- }
-- }
--
-- @Test(timeout = 30000)
-- public void testReplaceHandler() throws Exception {
-- switch (provider) {
-- case OPENSSL:
-- case OPENSSL_REFCNT:
-- final String sniHost = "sni.netty.io";
-- LocalAddress address = new LocalAddress("testReplaceHandler-" + Math.random());
-- EventLoopGroup group = new DefaultEventLoopGroup(1);
-- Channel sc = null;
-- Channel cc = null;
-- SslContext sslContext = null;
--
-- SelfSignedCertificate cert = new SelfSignedCertificate();
--
-- try {
-- final SslContext sslServerContext = SslContextBuilder
-- .forServer(cert.key(), cert.cert())
-- .sslProvider(provider)
-- .build();
--
-- final Mapping<String, SslContext> mapping = new Mapping<String, SslContext>() {
-- @Override
-- public SslContext map(String input) {
-- return sslServerContext;
-- }
-- };
--
-- final Promise<Void> releasePromise = group.next().newPromise();
--
-- final SniHandler handler = new SniHandler(mapping) {
-- @Override
-- protected void replaceHandler(ChannelHandlerContext ctx,
-- String hostname, final SslContext sslContext)
-- throws Exception {
--
-- boolean success = false;
-- try {
-- // The SniHandler's replaceHandler() method allows us to implement custom behavior.
-- // As an example, we want to release() the SslContext upon channelInactive() or rather
-- // when the SslHandler closes it's SslEngine. If you take a close look at SslHandler
-- // you'll see that it's doing it in the #handlerRemoved0() method.
--
-- SSLEngine sslEngine = sslContext.newEngine(ctx.alloc());
-- try {
-- SslHandler customSslHandler = new CustomSslHandler(sslContext, sslEngine) {
-- @Override
-- public void handlerRemoved0(ChannelHandlerContext ctx) throws Exception {
-- try {
-- super.handlerRemoved0(ctx);
-- } finally {
-- releasePromise.trySuccess(null);
-- }
-- }
-- };
-- ctx.pipeline().replace(this, CustomSslHandler.class.getName(), customSslHandler);
-- success = true;
-- } finally {
-- if (!success) {
-- ReferenceCountUtil.safeRelease(sslEngine);
-- }
-- }
-- } finally {
-- if (!success) {
-- ReferenceCountUtil.safeRelease(sslContext);
-- releasePromise.cancel(true);
-- }
-- }
-- }
-- };
--
-- ServerBootstrap sb = new ServerBootstrap();
-- sc = sb.group(group).channel(LocalServerChannel.class)
-- .childHandler(new ChannelInitializer<Channel>() {
-- @Override
-- protected void initChannel(Channel ch) throws Exception {
-- ch.pipeline().addFirst(handler);
-- }
-- }).bind(address).syncUninterruptibly().channel();
--
-- sslContext = SslContextBuilder.forClient().sslProvider(provider)
-- .trustManager(InsecureTrustManagerFactory.INSTANCE).build();
--
-- Bootstrap cb = new Bootstrap();
-- cc = cb.group(group).channel(LocalChannel.class).handler(new SslHandler(
-- sslContext.newEngine(ByteBufAllocator.DEFAULT, sniHost, -1)))
-- .connect(address).syncUninterruptibly().channel();
--
-- cc.writeAndFlush(Unpooled.wrappedBuffer("Hello, World!".getBytes()))
-- .syncUninterruptibly();
--
-- // Notice how the server's SslContext refCnt is 1
-- assertEquals(1, ((ReferenceCounted) sslServerContext).refCnt());
--
-- // The client disconnects
-- cc.close().syncUninterruptibly();
-- if (!releasePromise.awaitUninterruptibly(10L, TimeUnit.SECONDS)) {
-- throw new IllegalStateException("It doesn't seem #replaceHandler() got called.");
-- }
-
-- // We should have successfully release() the SslContext
-- assertEquals(0, ((ReferenceCounted) sslServerContext).refCnt());
-- } finally {
-- if (cc != null) {
-- cc.close().syncUninterruptibly();
-- }
-- if (sc != null) {
-- sc.close().syncUninterruptibly();
-- }
-- if (sslContext != null) {
-- ReferenceCountUtil.release(sslContext);
+- @Override
+- public String getProtocol() {
+- String protocol = this.protocol;
+- if (protocol == null) {
+- synchronized (ReferenceCountedOpenSslEngine.this) {
+- if (!isDestroyed()) {
+- protocol = SSL.getVersion(ssl);
+- } else {
+- protocol = StringUtil.EMPTY_STRING;
- }
-- group.shutdownGracefully();
--
-- cert.delete();
- }
-- case JDK:
-- return;
-- default:
-- throw new Error();
+- }
+- return protocol;
- }
-- }
--
-- /**
-- * This is a {@link SslHandler} that will call {@code release()} on the {@link SslContext} when
-- * the client disconnects.
-- *
-- * @see SniHandlerTest#testReplaceHandler()
-- */
-- private static class CustomSslHandler extends SslHandler {
-- private final SslContext sslContext;
-
-- public CustomSslHandler(SslContext sslContext, SSLEngine sslEngine) {
-- super(sslEngine);
-- this.sslContext = ObjectUtil.checkNotNull(sslContext, "sslContext");
+- @Override
+- public String getPeerHost() {
+- return ReferenceCountedOpenSslEngine.this.getPeerHost();
- }
-
- @Override
-- public void handlerRemoved0(ChannelHandlerContext ctx) throws Exception {
-- super.handlerRemoved0(ctx);
-- ReferenceCountUtil.release(sslContext);
+- public int getPeerPort() {
+- return ReferenceCountedOpenSslEngine.this.getPeerPort();
- }
-- }
-
-- private static void releaseAll(SslContext... contexts) {
-- for (SslContext ctx: contexts) {
-- ReferenceCountUtil.release(ctx);
+- @Override
+- public int getPacketBufferSize() {
+- return maxEncryptedPacketLength();
- }
-- }
--}
-diff --git a/handler/src/test/java/io/netty/handler/ssl/SslContextBuilderTest.java b/handler/src/test/java/io/netty/handler/ssl/SslContextBuilderTest.java
-deleted file mode 100644
-index 752424c..0000000
---- a/handler/src/test/java/io/netty/handler/ssl/SslContextBuilderTest.java
-+++ /dev/null
-@@ -1,132 +0,0 @@
--/*
-- * Copyright 2015 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
--
--import static org.junit.Assert.assertFalse;
--import static org.junit.Assert.assertTrue;
-
--import io.netty.buffer.UnpooledByteBufAllocator;
--import io.netty.handler.ssl.util.SelfSignedCertificate;
--import org.junit.Assume;
--import org.junit.Test;
--
--import javax.net.ssl.SSLEngine;
+- @Override
+- public int getApplicationBufferSize() {
+- return applicationBufferSize;
+- }
-
--public class SslContextBuilderTest {
--
-- @Test
-- public void testClientContextFromFileJdk() throws Exception {
-- testClientContextFromFile(SslProvider.JDK);
-- }
--
-- @Test
-- public void testClientContextFromFileOpenssl() throws Exception {
-- Assume.assumeTrue(OpenSsl.isAvailable());
-- testClientContextFromFile(SslProvider.OPENSSL);
-- }
--
-- @Test
-- public void testClientContextJdk() throws Exception {
-- testClientContext(SslProvider.JDK);
-- }
--
-- @Test
-- public void testClientContextOpenssl() throws Exception {
-- Assume.assumeTrue(OpenSsl.isAvailable());
-- testClientContext(SslProvider.OPENSSL);
-- }
--
-- @Test
-- public void testServerContextFromFileJdk() throws Exception {
-- testServerContextFromFile(SslProvider.JDK);
-- }
--
-- @Test
-- public void testServerContextFromFileOpenssl() throws Exception {
-- Assume.assumeTrue(OpenSsl.isAvailable());
-- testServerContextFromFile(SslProvider.OPENSSL);
-- }
--
-- @Test
-- public void testServerContextJdk() throws Exception {
-- testServerContext(SslProvider.JDK);
-- }
--
-- @Test
-- public void testServerContextOpenssl() throws Exception {
-- Assume.assumeTrue(OpenSsl.isAvailable());
-- testServerContext(SslProvider.OPENSSL);
-- }
--
-- private static void testClientContextFromFile(SslProvider provider) throws Exception {
-- SelfSignedCertificate cert = new SelfSignedCertificate();
-- SslContextBuilder builder = SslContextBuilder.forClient()
-- .sslProvider(provider)
-- .keyManager(cert.certificate(),
-- cert.privateKey())
-- .trustManager(cert.certificate())
-- .clientAuth(ClientAuth.OPTIONAL);
-- SslContext context = builder.build();
-- SSLEngine engine = context.newEngine(UnpooledByteBufAllocator.DEFAULT);
-- assertFalse(engine.getWantClientAuth());
-- assertFalse(engine.getNeedClientAuth());
-- engine.closeInbound();
-- engine.closeOutbound();
-- }
--
-- private static void testClientContext(SslProvider provider) throws Exception {
-- SelfSignedCertificate cert = new SelfSignedCertificate();
-- SslContextBuilder builder = SslContextBuilder.forClient()
-- .sslProvider(provider)
-- .keyManager(cert.key(), cert.cert())
-- .trustManager(cert.cert())
-- .clientAuth(ClientAuth.OPTIONAL);
-- SslContext context = builder.build();
-- SSLEngine engine = context.newEngine(UnpooledByteBufAllocator.DEFAULT);
-- assertFalse(engine.getWantClientAuth());
-- assertFalse(engine.getNeedClientAuth());
-- engine.closeInbound();
-- engine.closeOutbound();
-- }
--
-- private static void testServerContextFromFile(SslProvider provider) throws Exception {
-- SelfSignedCertificate cert = new SelfSignedCertificate();
-- SslContextBuilder builder = SslContextBuilder.forServer(cert.certificate(), cert.privateKey())
-- .sslProvider(provider)
-- .trustManager(cert.certificate())
-- .clientAuth(ClientAuth.OPTIONAL);
-- SslContext context = builder.build();
-- SSLEngine engine = context.newEngine(UnpooledByteBufAllocator.DEFAULT);
-- assertTrue(engine.getWantClientAuth());
-- assertFalse(engine.getNeedClientAuth());
-- engine.closeInbound();
-- engine.closeOutbound();
-- }
--
-- private static void testServerContext(SslProvider provider) throws Exception {
-- SelfSignedCertificate cert = new SelfSignedCertificate();
-- SslContextBuilder builder = SslContextBuilder.forServer(cert.key(), cert.cert())
-- .sslProvider(provider)
-- .trustManager(cert.cert())
-- .clientAuth(ClientAuth.REQUIRE);
-- SslContext context = builder.build();
-- SSLEngine engine = context.newEngine(UnpooledByteBufAllocator.DEFAULT);
-- assertFalse(engine.getWantClientAuth());
-- assertTrue(engine.getNeedClientAuth());
-- engine.closeInbound();
-- engine.closeOutbound();
+- @Override
+- public void tryExpandApplicationBufferSize(int packetLengthDataOnly) {
+- if (packetLengthDataOnly > MAX_PLAINTEXT_LENGTH && applicationBufferSize != MAX_RECORD_SIZE) {
+- applicationBufferSize = MAX_RECORD_SIZE;
+- }
+- }
- }
-}
-diff --git a/handler/src/test/java/io/netty/handler/ssl/SslErrorTest.java b/handler/src/test/java/io/netty/handler/ssl/SslErrorTest.java
+diff --git a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslServerContext.java b/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslServerContext.java
deleted file mode 100644
-index aacdb69..0000000
---- a/handler/src/test/java/io/netty/handler/ssl/SslErrorTest.java
+index bac027a3b4..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslServerContext.java
+++ /dev/null
-@@ -1,255 +0,0 @@
+@@ -1,286 +0,0 @@
-/*
- * Copyright 2016 The Netty Project
- *
@@ -8134,351 +8008,449 @@ index aacdb69..0000000
- */
-package io.netty.handler.ssl;
-
--import io.netty.bootstrap.Bootstrap;
--import io.netty.bootstrap.ServerBootstrap;
--import io.netty.channel.Channel;
--import io.netty.channel.ChannelHandlerContext;
--import io.netty.channel.ChannelInboundHandlerAdapter;
--import io.netty.channel.ChannelInitializer;
--import io.netty.channel.EventLoopGroup;
--import io.netty.channel.nio.NioEventLoopGroup;
--import io.netty.channel.socket.nio.NioServerSocketChannel;
--import io.netty.channel.socket.nio.NioSocketChannel;
--import io.netty.handler.logging.LogLevel;
--import io.netty.handler.logging.LoggingHandler;
--import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
--import io.netty.handler.ssl.util.SelfSignedCertificate;
--import io.netty.handler.ssl.util.SimpleTrustManagerFactory;
--import io.netty.util.ReferenceCountUtil;
--import io.netty.util.concurrent.Promise;
--import io.netty.util.internal.EmptyArrays;
--import org.junit.Assume;
--import org.junit.Test;
--import org.junit.runner.RunWith;
--import org.junit.runners.Parameterized;
+-import io.netty.buffer.ByteBufAllocator;
+-import io.netty.internal.tcnative.CertificateCallback;
+-import io.netty.internal.tcnative.SSL;
+-import io.netty.internal.tcnative.SSLContext;
+-import io.netty.internal.tcnative.SniHostNameMatcher;
+-import io.netty.util.CharsetUtil;
+-import io.netty.util.internal.PlatformDependent;
+-import io.netty.util.internal.SuppressJava6Requirement;
+-import io.netty.util.internal.SystemPropertyUtil;
+-import io.netty.util.internal.logging.InternalLogger;
+-import io.netty.util.internal.logging.InternalLoggerFactory;
-
--import javax.net.ssl.ManagerFactoryParameters;
--import javax.net.ssl.SSLException;
--import javax.net.ssl.TrustManager;
--import javax.net.ssl.X509TrustManager;
--import javax.security.auth.x500.X500Principal;
--import java.io.File;
-import java.security.KeyStore;
--import java.security.cert.CRLReason;
--import java.security.cert.CertPathValidatorException;
--import java.security.cert.CertificateException;
--import java.security.cert.CertificateExpiredException;
--import java.security.cert.CertificateNotYetValidException;
--import java.security.cert.CertificateRevokedException;
--import java.security.cert.Extension;
+-import java.security.PrivateKey;
-import java.security.cert.X509Certificate;
--import java.util.ArrayList;
--import java.util.Collection;
--import java.util.Collections;
--import java.util.Date;
--import java.util.List;
--import java.util.Locale;
+-import javax.net.ssl.KeyManagerFactory;
+-import javax.net.ssl.SSLException;
+-import javax.net.ssl.TrustManagerFactory;
+-import javax.net.ssl.X509ExtendedTrustManager;
+-import javax.net.ssl.X509TrustManager;
-
+-import static io.netty.util.internal.ObjectUtil.checkNotNull;
-
--(a)RunWith(Parameterized.class)
--public class SslErrorTest {
+-/**
+- * A server-side {@link SslContext} which uses OpenSSL's SSL/TLS implementation.
+- * <p>Instances of this class must be {@link #release() released} or else native memory will leak!
+- *
+- * <p>Instances of this class <strong>must not</strong> be released before any {@link ReferenceCountedOpenSslEngine}
+- * which depends upon the instance of this class is released. Otherwise if any method of
+- * {@link ReferenceCountedOpenSslEngine} is called which uses this class's JNI resources the JVM may crash.
+- */
+-public final class ReferenceCountedOpenSslServerContext extends ReferenceCountedOpenSslContext {
+- private static final InternalLogger logger =
+- InternalLoggerFactory.getInstance(ReferenceCountedOpenSslServerContext.class);
+- private static final byte[] ID = {'n', 'e', 't', 't', 'y'};
+- private final OpenSslServerSessionContext sessionContext;
-
-- @Parameterized.Parameters(name = "{index}: serverProvider = {0}, clientProvider = {1}, exception = {2}")
-- public static Collection<Object[]> data() {
-- List<SslProvider> serverProviders = new ArrayList<SslProvider>(2);
-- List<SslProvider> clientProviders = new ArrayList<SslProvider>(3);
+- private static final boolean ENABLE_SESSION_TICKET =
+- SystemPropertyUtil.getBoolean("jdk.tls.server.enableSessionTicketExtension", false);
-
-- if (OpenSsl.isAvailable()) {
-- serverProviders.add(SslProvider.OPENSSL);
-- serverProviders.add(SslProvider.OPENSSL_REFCNT);
-- clientProviders.add(SslProvider.OPENSSL);
-- clientProviders.add(SslProvider.OPENSSL_REFCNT);
-- }
-- // We not test with SslProvider.JDK on the server side as the JDK implementation currently just send the same
-- // alert all the time, sigh.....
-- clientProviders.add(SslProvider.JDK);
--
-- List<CertificateException> exceptions = new ArrayList<CertificateException>(6);
-- exceptions.add(new CertificateExpiredException());
-- exceptions.add(new CertificateNotYetValidException());
-- exceptions.add(new CertificateRevokedException(
-- new Date(), CRLReason.AA_COMPROMISE, new X500Principal(""),
-- Collections.<String, Extension>emptyMap()));
--
-- // Also use wrapped exceptions as this is what the JDK implementation of X509TrustManagerFactory is doing.
-- exceptions.add(newCertificateException(CertPathValidatorException.BasicReason.EXPIRED));
-- exceptions.add(newCertificateException(CertPathValidatorException.BasicReason.NOT_YET_VALID));
-- exceptions.add(newCertificateException(CertPathValidatorException.BasicReason.REVOKED));
--
-- List<Object[]> params = new ArrayList<Object[]>();
-- for (SslProvider serverProvider: serverProviders) {
-- for (SslProvider clientProvider: clientProviders) {
-- for (CertificateException exception: exceptions) {
-- params.add(new Object[] { serverProvider, clientProvider, exception});
-- }
+- ReferenceCountedOpenSslServerContext(
+- X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory,
+- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory,
+- Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
+- long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[] protocols, boolean startTls,
+- boolean enableOcsp, String keyStore) throws SSLException {
+- this(trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory, ciphers,
+- cipherFilter, toNegotiator(apn), sessionCacheSize, sessionTimeout, clientAuth, protocols, startTls,
+- enableOcsp, keyStore);
+- }
+-
+- ReferenceCountedOpenSslServerContext(
+- X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory,
+- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory,
+- Iterable<String> ciphers, CipherSuiteFilter cipherFilter, OpenSslApplicationProtocolNegotiator apn,
+- long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[] protocols, boolean startTls,
+- boolean enableOcsp, String keyStore) throws SSLException {
+- super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, SSL.SSL_MODE_SERVER, keyCertChain,
+- clientAuth, protocols, startTls, enableOcsp, true);
+- // Create a new SSL_CTX and configure it.
+- boolean success = false;
+- try {
+- sessionContext = newSessionContext(this, ctx, engineMap, trustCertCollection, trustManagerFactory,
+- keyCertChain, key, keyPassword, keyManagerFactory, keyStore);
+- if (ENABLE_SESSION_TICKET) {
+- sessionContext.setTicketKeys();
+- }
+- success = true;
+- } finally {
+- if (!success) {
+- release();
- }
- }
-- return params;
- }
-
-- private static CertificateException newCertificateException(CertPathValidatorException.Reason reason) {
-- return new TestCertificateException(
-- new CertPathValidatorException("x", null, null, -1, reason));
+- @Override
+- public OpenSslServerSessionContext sessionContext() {
+- return sessionContext;
- }
-
-- private final SslProvider serverProvider;
-- private final SslProvider clientProvider;
-- private final CertificateException exception;
+- static OpenSslServerSessionContext newSessionContext(ReferenceCountedOpenSslContext thiz, long ctx,
+- OpenSslEngineMap engineMap,
+- X509Certificate[] trustCertCollection,
+- TrustManagerFactory trustManagerFactory,
+- X509Certificate[] keyCertChain, PrivateKey key,
+- String keyPassword, KeyManagerFactory keyManagerFactory,
+- String keyStore)
+- throws SSLException {
+- OpenSslKeyMaterialProvider keyMaterialProvider = null;
+- try {
+- try {
+- SSLContext.setVerify(ctx, SSL.SSL_CVERIFY_NONE, VERIFY_DEPTH);
+- if (!OpenSsl.useKeyManagerFactory()) {
+- if (keyManagerFactory != null) {
+- throw new IllegalArgumentException(
+- "KeyManagerFactory not supported");
+- }
+- checkNotNull(keyCertChain, "keyCertChain");
-
-- public SslErrorTest(SslProvider serverProvider, SslProvider clientProvider, CertificateException exception) {
-- this.serverProvider = serverProvider;
-- this.clientProvider = clientProvider;
-- this.exception = exception;
-- }
+- setKeyMaterial(ctx, keyCertChain, key, keyPassword);
+- } else {
+- // javadocs state that keyManagerFactory has precedent over keyCertChain, and we must have a
+- // keyManagerFactory for the server so build one if it is not specified.
+- if (keyManagerFactory == null) {
+- char[] keyPasswordChars = keyStorePassword(keyPassword);
+- KeyStore ks = buildKeyStore(keyCertChain, key, keyPasswordChars, keyStore);
+- if (ks.aliases().hasMoreElements()) {
+- keyManagerFactory = new OpenSslX509KeyManagerFactory();
+- } else {
+- keyManagerFactory = new OpenSslCachingX509KeyManagerFactory(
+- KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()));
+- }
+- keyManagerFactory.init(ks, keyPasswordChars);
+- }
+- keyMaterialProvider = providerFor(keyManagerFactory, keyPassword);
-
-- @Test(timeout = 30000)
-- public void testCorrectAlert() throws Exception {
-- // As this only works correctly at the moment when OpenSslEngine is used on the server-side there is
-- // no need to run it if there is no openssl is available at all.
-- Assume.assumeTrue(OpenSsl.isAvailable());
+- SSLContext.setCertificateCallback(ctx, new OpenSslServerCertificateCallback(
+- engineMap, new OpenSslKeyMaterialManager(keyMaterialProvider)));
+- }
+- } catch (Exception e) {
+- throw new SSLException("failed to set certificate and key", e);
+- }
+- try {
+- if (trustCertCollection != null) {
+- trustManagerFactory = buildTrustManagerFactory(trustCertCollection, trustManagerFactory, keyStore);
+- } else if (trustManagerFactory == null) {
+- // Mimic the way SSLContext.getInstance(KeyManager[], null, null) works
+- trustManagerFactory = TrustManagerFactory.getInstance(
+- TrustManagerFactory.getDefaultAlgorithm());
+- trustManagerFactory.init((KeyStore) null);
+- }
-
-- SelfSignedCertificate ssc = new SelfSignedCertificate();
-- final SslContext sslServerCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey())
-- .sslProvider(serverProvider)
-- .trustManager(new SimpleTrustManagerFactory() {
-- @Override
-- protected void engineInit(KeyStore keyStore) { }
-- @Override
-- protected void engineInit(ManagerFactoryParameters managerFactoryParameters) { }
+- final X509TrustManager manager = chooseTrustManager(trustManagerFactory.getTrustManagers());
-
-- @Override
-- protected TrustManager[] engineGetTrustManagers() {
-- return new TrustManager[] { new X509TrustManager() {
+- // IMPORTANT: The callbacks set for verification must be static to prevent memory leak as
+- // otherwise the context can never be collected. This is because the JNI code holds
+- // a global reference to the callbacks.
+- //
+- // See https://github.com/netty/netty/issues/5372
-
-- @Override
-- public void checkClientTrusted(X509Certificate[] x509Certificates, String s)
-- throws CertificateException {
-- throw exception;
-- }
+- setVerifyCallback(ctx, engineMap, manager);
-
-- @Override
-- public void checkServerTrusted(X509Certificate[] x509Certificates, String s)
-- throws CertificateException {
-- // NOOP
+- X509Certificate[] issuers = manager.getAcceptedIssuers();
+- if (issuers != null && issuers.length > 0) {
+- long bio = 0;
+- try {
+- bio = toBIO(ByteBufAllocator.DEFAULT, issuers);
+- if (!SSLContext.setCACertificateBio(ctx, bio)) {
+- throw new SSLException("unable to setup accepted issuers for trustmanager " + manager);
+- }
+- } finally {
+- freeBio(bio);
- }
+- }
-
-- @Override
-- public X509Certificate[] getAcceptedIssuers() {
-- return EmptyArrays.EMPTY_X509_CERTIFICATES;
-- }
-- } };
+- if (PlatformDependent.javaVersion() >= 8) {
+- // Only do on Java8+ as SNIMatcher is not supported in earlier releases.
+- // IMPORTANT: The callbacks set for hostname matching must be static to prevent memory leak as
+- // otherwise the context can never be collected. This is because the JNI code holds
+- // a global reference to the matcher.
+- SSLContext.setSniHostnameMatcher(ctx, new OpenSslSniHostnameMatcher(engineMap));
+- }
+- } catch (SSLException e) {
+- throw e;
+- } catch (Exception e) {
+- throw new SSLException("unable to setup trustmanager", e);
- }
-- }).clientAuth(ClientAuth.REQUIRE).build();
-
-- final SslContext sslClientCtx = SslContextBuilder.forClient()
-- .trustManager(InsecureTrustManagerFactory.INSTANCE)
-- .keyManager(new File(getClass().getResource("test.crt").getFile()),
-- new File(getClass().getResource("test_unencrypted.pem").getFile()))
-- .sslProvider(clientProvider).build();
+- OpenSslServerSessionContext sessionContext = new OpenSslServerSessionContext(thiz, keyMaterialProvider);
+- sessionContext.setSessionIdContext(ID);
-
-- Channel serverChannel = null;
-- Channel clientChannel = null;
-- EventLoopGroup group = new NioEventLoopGroup();
-- try {
-- serverChannel = new ServerBootstrap().group(group)
-- .channel(NioServerSocketChannel.class)
-- .handler(new LoggingHandler(LogLevel.INFO))
-- .childHandler(new ChannelInitializer<Channel>() {
-- @Override
-- protected void initChannel(Channel ch) throws Exception {
-- ch.pipeline().addLast(sslServerCtx.newHandler(ch.alloc()));
-- ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {
--
-- @Override
-- public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
-- ctx.close();
-- }
-- });
-- }
-- }).bind(0).sync().channel();
--
-- final Promise<Void> promise = group.next().newPromise();
--
-- clientChannel = new Bootstrap().group(group)
-- .channel(NioSocketChannel.class)
-- .handler(new ChannelInitializer<Channel>() {
-- @Override
-- protected void initChannel(Channel ch) throws Exception {
-- ch.pipeline().addLast(sslClientCtx.newHandler(ch.alloc()));
-- ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {
-- @Override
-- public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
-- // Unwrap as its wrapped by a DecoderException
-- Throwable unwrappedCause = cause.getCause();
-- if (unwrappedCause instanceof SSLException) {
-- if (exception instanceof TestCertificateException) {
-- CertPathValidatorException.Reason reason =
-- ((CertPathValidatorException) exception.getCause()).getReason();
-- if (reason == CertPathValidatorException.BasicReason.EXPIRED) {
-- verifyException(unwrappedCause, "expired", promise);
-- } else if (reason == CertPathValidatorException.BasicReason.NOT_YET_VALID) {
-- verifyException(unwrappedCause, "bad", promise);
-- } else if (reason == CertPathValidatorException.BasicReason.REVOKED) {
-- verifyException(unwrappedCause, "revoked", promise);
-- }
-- } else if (exception instanceof CertificateExpiredException) {
-- verifyException(unwrappedCause, "expired", promise);
-- } else if (exception instanceof CertificateNotYetValidException) {
-- verifyException(unwrappedCause, "bad", promise);
-- } else if (exception instanceof CertificateRevokedException) {
-- verifyException(unwrappedCause, "revoked", promise);
-- }
-- }
-- }
-- });
-- }
-- }).connect(serverChannel.localAddress()).syncUninterruptibly().channel();
-- // Block until we received the correct exception
-- promise.syncUninterruptibly();
+- keyMaterialProvider = null;
+-
+- return sessionContext;
- } finally {
-- if (clientChannel != null) {
-- clientChannel.close().syncUninterruptibly();
-- }
-- if (serverChannel != null) {
-- serverChannel.close().syncUninterruptibly();
+- if (keyMaterialProvider != null) {
+- keyMaterialProvider.destroy();
- }
-- group.shutdownGracefully();
--
-- ReferenceCountUtil.release(sslServerCtx);
-- ReferenceCountUtil.release(sslClientCtx);
- }
- }
-
-- // Its a bit hacky to verify against the message that is part of the exception but there is no other way
-- // at the moment as there are no different exceptions for the different alerts.
-- private static void verifyException(Throwable cause, String messagePart, Promise<Void> promise) {
-- String message = cause.getMessage();
-- if (message.toLowerCase(Locale.UK).contains(messagePart.toLowerCase(Locale.UK))) {
-- promise.setSuccess(null);
+- @SuppressJava6Requirement(reason = "Guarded by java version check")
+- private static void setVerifyCallback(long ctx, OpenSslEngineMap engineMap, X509TrustManager manager) {
+- // Use this to prevent an error when running on java < 7
+- if (useExtendedTrustManager(manager)) {
+- SSLContext.setCertVerifyCallback(ctx, new ExtendedTrustManagerVerifyCallback(
+- engineMap, (X509ExtendedTrustManager) manager));
- } else {
-- promise.setFailure(new AssertionError("message not contains '" + messagePart + "': " + message));
+- SSLContext.setCertVerifyCallback(ctx, new TrustManagerVerifyCallback(engineMap, manager));
- }
- }
-
-- private static final class TestCertificateException extends CertificateException {
+- private static final class OpenSslServerCertificateCallback implements CertificateCallback {
+- private final OpenSslEngineMap engineMap;
+- private final OpenSslKeyMaterialManager keyManagerHolder;
-
-- public TestCertificateException(Throwable cause) {
-- super(cause);
+- OpenSslServerCertificateCallback(OpenSslEngineMap engineMap, OpenSslKeyMaterialManager keyManagerHolder) {
+- this.engineMap = engineMap;
+- this.keyManagerHolder = keyManagerHolder;
- }
-- }
--}
-diff --git a/handler/src/test/java/io/netty/handler/ssl/SslHandlerTest.java b/handler/src/test/java/io/netty/handler/ssl/SslHandlerTest.java
-index 5ef43de..52c4d22 100644
---- a/handler/src/test/java/io/netty/handler/ssl/SslHandlerTest.java
-+++ b/handler/src/test/java/io/netty/handler/ssl/SslHandlerTest.java
-@@ -121,35 +121,6 @@ public class SslHandlerTest {
- }
- }
-
-- @Test
-- public void testReleaseSslEngine() throws Exception {
-- assumeTrue(OpenSsl.isAvailable());
-
-- SelfSignedCertificate cert = new SelfSignedCertificate();
-- try {
-- SslContext sslContext = SslContextBuilder.forServer(cert.certificate(), cert.privateKey())
-- .sslProvider(SslProvider.OPENSSL)
-- .build();
+- @Override
+- public void handle(long ssl, byte[] keyTypeBytes, byte[][] asn1DerEncodedPrincipals) throws Exception {
+- final ReferenceCountedOpenSslEngine engine = engineMap.get(ssl);
+- if (engine == null) {
+- // Maybe null if destroyed in the meantime.
+- return;
+- }
- try {
-- SSLEngine sslEngine = sslContext.newEngine(ByteBufAllocator.DEFAULT);
-- EmbeddedChannel ch = new EmbeddedChannel(new SslHandler(sslEngine));
+- // For now we just ignore the asn1DerEncodedPrincipals as this is kind of inline with what the
+- // OpenJDK SSLEngineImpl does.
+- keyManagerHolder.setKeyMaterialServerSide(engine);
+- } catch (Throwable cause) {
+- logger.debug("Failed to set the server-side key material", cause);
+- engine.initHandshakeException(cause);
+- }
+- }
+- }
-
-- assertEquals(1, ((ReferenceCounted) sslContext).refCnt());
-- assertEquals(1, ((ReferenceCounted) sslEngine).refCnt());
+- private static final class TrustManagerVerifyCallback extends AbstractCertificateVerifier {
+- private final X509TrustManager manager;
-
-- assertTrue(ch.finishAndReleaseAll());
-- ch.close().syncUninterruptibly();
+- TrustManagerVerifyCallback(OpenSslEngineMap engineMap, X509TrustManager manager) {
+- super(engineMap);
+- this.manager = manager;
+- }
-
-- assertEquals(1, ((ReferenceCounted) sslContext).refCnt());
-- assertEquals(0, ((ReferenceCounted) sslEngine).refCnt());
-- } finally {
-- ReferenceCountUtil.release(sslContext);
-- }
-- } finally {
-- cert.delete();
+- @Override
+- void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts, String auth)
+- throws Exception {
+- manager.checkClientTrusted(peerCerts, auth);
- }
- }
-
- private static final class TlsReadTest extends ChannelOutboundHandlerAdapter {
- private volatile boolean readIssued;
-
-@@ -279,13 +250,6 @@ public class SslHandlerTest {
- testAlertProducedAndSend(SslProvider.JDK);
- }
-
-- @Test(timeout = 30000)
-- public void testAlertProducedAndSendOpenSsl() throws Exception {
-- assumeTrue(OpenSsl.isAvailable());
-- testAlertProducedAndSend(SslProvider.OPENSSL);
-- testAlertProducedAndSend(SslProvider.OPENSSL_REFCNT);
+- @SuppressJava6Requirement(reason = "Usage guarded by java version check")
+- private static final class ExtendedTrustManagerVerifyCallback extends AbstractCertificateVerifier {
+- private final X509ExtendedTrustManager manager;
+-
+- ExtendedTrustManagerVerifyCallback(OpenSslEngineMap engineMap, X509ExtendedTrustManager manager) {
+- super(engineMap);
+- this.manager = OpenSslTlsv13X509ExtendedTrustManager.wrap(manager);
+- }
+-
+- @Override
+- void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts, String auth)
+- throws Exception {
+- manager.checkClientTrusted(peerCerts, auth, engine);
+- }
- }
-
- private void testAlertProducedAndSend(SslProvider provider) throws Exception {
- SelfSignedCertificate ssc = new SelfSignedCertificate();
-
-@@ -425,12 +389,6 @@ public class SslHandlerTest {
- testCloseNotify(SslProvider.JDK, 5000, false);
- }
-
-- @Test(timeout = 30000)
-- public void testCloseNotifyReceivedOpenSsl() throws Exception {
-- assumeTrue(OpenSsl.isAvailable());
-- testCloseNotify(SslProvider.OPENSSL, 5000, false);
-- testCloseNotify(SslProvider.OPENSSL_REFCNT, 5000, false);
+- private static final class OpenSslSniHostnameMatcher implements SniHostNameMatcher {
+- private final OpenSslEngineMap engineMap;
+-
+- OpenSslSniHostnameMatcher(OpenSslEngineMap engineMap) {
+- this.engineMap = engineMap;
+- }
+-
+- @Override
+- public boolean match(long ssl, String hostname) {
+- ReferenceCountedOpenSslEngine engine = engineMap.get(ssl);
+- if (engine != null) {
+- // TODO: In the next release of tcnative we should pass the byte[] directly in and not use a String.
+- return engine.checkSniHostnameMatch(hostname.getBytes(CharsetUtil.UTF_8));
+- }
+- logger.warn("No ReferenceCountedOpenSslEngine found for SSL pointer: {}", ssl);
+- return false;
+- }
- }
+-}
+diff --git a/handler/src/main/java/io/netty/handler/ssl/SslContext.java b/handler/src/main/java/io/netty/handler/ssl/SslContext.java
+index fef2702cfb..eb5110d145 100644
+--- a/handler/src/main/java/io/netty/handler/ssl/SslContext.java
++++ b/handler/src/main/java/io/netty/handler/ssl/SslContext.java
+@@ -120,11 +120,7 @@ public abstract class SslContext {
+ }
- @Test(timeout = 30000)
- public void testCloseNotifyReceivedJdkTimeout() throws Exception {
-@@ -438,24 +396,10 @@ public class SslHandlerTest {
+ private static SslProvider defaultProvider() {
+- if (OpenSsl.isAvailable()) {
+- return SslProvider.OPENSSL;
+- } else {
+- return SslProvider.JDK;
+- }
++ return SslProvider.JDK;
}
- @Test(timeout = 30000)
-- public void testCloseNotifyReceivedOpenSslTimeout() throws Exception {
-- assumeTrue(OpenSsl.isAvailable());
-- testCloseNotify(SslProvider.OPENSSL, 100, true);
-- testCloseNotify(SslProvider.OPENSSL_REFCNT, 100, true);
-- }
+ /**
+@@ -466,18 +462,6 @@ public abstract class SslContext {
+ trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword,
+ keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout,
+ clientAuth, protocols, startTls, keyStoreType);
+- case OPENSSL:
+- verifyNullSslContextProvider(provider, sslContextProvider);
+- return new OpenSslServerContext(
+- trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword,
+- keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout,
+- clientAuth, protocols, startTls, enableOcsp, keyStoreType);
+- case OPENSSL_REFCNT:
+- verifyNullSslContextProvider(provider, sslContextProvider);
+- return new ReferenceCountedOpenSslServerContext(
+- trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword,
+- keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout,
+- clientAuth, protocols, startTls, enableOcsp, keyStoreType);
+ default:
+ throw new Error(provider.toString());
+ }
+@@ -822,18 +806,6 @@ public abstract class SslContext {
+ trustCert, trustManagerFactory, keyCertChain, key, keyPassword,
+ keyManagerFactory, ciphers, cipherFilter, apn, protocols, sessionCacheSize,
+ sessionTimeout, keyStoreType);
+- case OPENSSL:
+- verifyNullSslContextProvider(provider, sslContextProvider);
+- return new OpenSslClientContext(
+- trustCert, trustManagerFactory, keyCertChain, key, keyPassword,
+- keyManagerFactory, ciphers, cipherFilter, apn, protocols, sessionCacheSize, sessionTimeout,
+- enableOcsp, keyStoreType);
+- case OPENSSL_REFCNT:
+- verifyNullSslContextProvider(provider, sslContextProvider);
+- return new ReferenceCountedOpenSslClientContext(
+- trustCert, trustManagerFactory, keyCertChain, key, keyPassword,
+- keyManagerFactory, ciphers, cipherFilter, apn, protocols, sessionCacheSize, sessionTimeout,
+- enableOcsp, keyStoreType);
+ default:
+ throw new Error(provider.toString());
+ }
+diff --git a/handler/src/main/java/io/netty/handler/ssl/SslHandler.java b/handler/src/main/java/io/netty/handler/ssl/SslHandler.java
+index 8e11bbf4cc..56be212b09 100644
+--- a/handler/src/main/java/io/netty/handler/ssl/SslHandler.java
++++ b/handler/src/main/java/io/netty/handler/ssl/SslHandler.java
+@@ -181,53 +181,6 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
+ private static final int MAX_PLAINTEXT_LENGTH = 16 * 1024;
+
+ private enum SslEngineType {
+- TCNATIVE(true, COMPOSITE_CUMULATOR) {
+- @Override
+- SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int len, ByteBuf out)
+- throws SSLException {
+- int nioBufferCount = in.nioBufferCount();
+- int writerIndex = out.writerIndex();
+- final SSLEngineResult result;
+- if (nioBufferCount > 1) {
+- /*
+- * If {@link OpenSslEngine} is in use,
+- * we can use a special {@link OpenSslEngine#unwrap(ByteBuffer[], ByteBuffer[])} method
+- * that accepts multiple {@link ByteBuffer}s without additional memory copies.
+- */
+- ReferenceCountedOpenSslEngine opensslEngine = (ReferenceCountedOpenSslEngine) handler.engine;
+- try {
+- handler.singleBuffer[0] = toByteBuffer(out, writerIndex,
+- out.writableBytes());
+- result = opensslEngine.unwrap(in.nioBuffers(readerIndex, len), handler.singleBuffer);
+- } finally {
+- handler.singleBuffer[0] = null;
+- }
+- } else {
+- result = handler.engine.unwrap(toByteBuffer(in, readerIndex, len),
+- toByteBuffer(out, writerIndex, out.writableBytes()));
+- }
+- out.writerIndex(writerIndex + result.bytesProduced());
+- return result;
+- }
-
-- @Test(timeout = 30000)
- public void testCloseNotifyNotWaitForResponseJdk() throws Exception {
- testCloseNotify(SslProvider.JDK, 0, false);
- }
+- @Override
+- ByteBuf allocateWrapBuffer(SslHandler handler, ByteBufAllocator allocator,
+- int pendingBytes, int numComponents) {
+- return allocator.directBuffer(((ReferenceCountedOpenSslEngine) handler.engine)
+- .calculateMaxLengthForWrap(pendingBytes, numComponents));
+- }
+-
+- @Override
+- int calculatePendingData(SslHandler handler, int guess) {
+- int sslPending = ((ReferenceCountedOpenSslEngine) handler.engine).sslPending();
+- return sslPending > 0 ? sslPending : guess;
+- }
+-
+- @Override
+- boolean jdkCompatibilityMode(SSLEngine engine) {
+- return ((ReferenceCountedOpenSslEngine) engine).jdkCompatibilityMode;
+- }
+- },
+ JDK(false, MERGE_CUMULATOR) {
+ @Override
+ SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int len, ByteBuf out)
+@@ -280,7 +233,7 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
+ };
+
+ static SslEngineType forEngine(SSLEngine engine) {
+- return engine instanceof ReferenceCountedOpenSslEngine ? TCNATIVE : JDK;
++ return JDK;
+ }
+
+ SslEngineType(boolean wantsDirectBuffer, Cumulator cumulator) {
+diff --git a/handler/src/main/java/io/netty/handler/ssl/SslMasterKeyHandler.java b/handler/src/main/java/io/netty/handler/ssl/SslMasterKeyHandler.java
+index b1c710c841..44ef0456ed 100644
+--- a/handler/src/main/java/io/netty/handler/ssl/SslMasterKeyHandler.java
++++ b/handler/src/main/java/io/netty/handler/ssl/SslMasterKeyHandler.java
+@@ -138,9 +138,6 @@ public abstract class SslMasterKeyHandler extends ChannelInboundHandlerAdapter {
+ "via reflection.", e);
+ }
+ accept(secretKey, sslSession);
+- } else if (OpenSsl.isAvailable() && engine instanceof ReferenceCountedOpenSslEngine) {
+- SecretKeySpec secretKey = ((ReferenceCountedOpenSslEngine) engine).masterKey();
+- accept(secretKey, sslSession);
+ }
+ }
+ }
+diff --git a/handler/src/main/java/io/netty/handler/ssl/SslProvider.java b/handler/src/main/java/io/netty/handler/ssl/SslProvider.java
+index e72cfed8d9..5263314e7c 100644
+--- a/handler/src/main/java/io/netty/handler/ssl/SslProvider.java
++++ b/handler/src/main/java/io/netty/handler/ssl/SslProvider.java
+@@ -26,16 +26,7 @@ public enum SslProvider {
+ /**
+ * JDK's default implementation.
+ */
+- JDK,
+- /**
+- * OpenSSL-based implementation.
+- */
+- OPENSSL,
+- /**
+- * OpenSSL-based implementation which does not have finalizers and instead implements {@link ReferenceCounted}.
+- */
+- @UnstableApi
+- OPENSSL_REFCNT;
++ JDK;
-- @Test(timeout = 30000)
-- public void testCloseNotifyNotWaitForResponseOpenSsl() throws Exception {
-- assumeTrue(OpenSsl.isAvailable());
-- testCloseNotify(SslProvider.OPENSSL, 0, false);
-- testCloseNotify(SslProvider.OPENSSL_REFCNT, 0, false);
-- }
--
- private static void testCloseNotify(SslProvider provider, final long closeNotifyReadTimeout, final boolean timeout)
- throws Exception {
- SelfSignedCertificate ssc = new SelfSignedCertificate();
-@@ -720,7 +664,7 @@ public class SslHandlerTest {
+ /**
+ * Returns {@code true} if the specified {@link SslProvider} supports
+@@ -45,9 +36,6 @@ public enum SslProvider {
switch (provider) {
- case OPENSSL:
- case OPENSSL_REFCNT:
-- return OpenSsl.isAvailable();
-+ return false;
+ case JDK:
+ return JdkAlpnApplicationProtocolNegotiator.isAlpnSupported();
+- case OPENSSL:
+- case OPENSSL_REFCNT:
+- return OpenSsl.isAlpnSupported();
default:
- return true;
+ throw new Error("Unknown SslProvider: " + provider);
}
-diff --git a/handler/src/test/java/io/netty/handler/ssl/ocsp/OcspTest.java b/handler/src/test/java/io/netty/handler/ssl/ocsp/OcspTest.java
+diff --git a/handler/src/main/java/io/netty/handler/ssl/ocsp/OcspClientHandler.java b/handler/src/main/java/io/netty/handler/ssl/ocsp/OcspClientHandler.java
deleted file mode 100644
-index 4aecc74..0000000
---- a/handler/src/test/java/io/netty/handler/ssl/ocsp/OcspTest.java
+index c45c50e1e3..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/ocsp/OcspClientHandler.java
+++ /dev/null
-@@ -1,501 +0,0 @@
+@@ -1,61 +0,0 @@
-/*
- * Copyright 2017 The Netty Project
- *
@@ -8494,492 +8466,102 @@ index 4aecc74..0000000
- * License for the specific language governing permissions and limitations
- * under the License.
- */
--
-package io.netty.handler.ssl.ocsp;
-
--import io.netty.bootstrap.Bootstrap;
--import io.netty.bootstrap.ServerBootstrap;
--import io.netty.buffer.ByteBufAllocator;
--import io.netty.buffer.Unpooled;
--import io.netty.channel.Channel;
--import io.netty.channel.ChannelHandler;
-import io.netty.channel.ChannelHandlerContext;
-import io.netty.channel.ChannelInboundHandlerAdapter;
--import io.netty.channel.ChannelInitializer;
--import io.netty.channel.ChannelPipeline;
--import io.netty.channel.DefaultEventLoopGroup;
--import io.netty.channel.EventLoopGroup;
--import io.netty.channel.local.LocalAddress;
--import io.netty.channel.local.LocalChannel;
--import io.netty.channel.local.LocalServerChannel;
--import io.netty.handler.ssl.OpenSsl;
+-import io.netty.handler.ssl.ReferenceCountedOpenSslContext;
-import io.netty.handler.ssl.ReferenceCountedOpenSslEngine;
--import io.netty.handler.ssl.SslContext;
--import io.netty.handler.ssl.SslContextBuilder;
--import io.netty.handler.ssl.SslHandler;
--import io.netty.handler.ssl.SslProvider;
--import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
--import io.netty.handler.ssl.util.SelfSignedCertificate;
--import io.netty.util.CharsetUtil;
--import io.netty.util.ReferenceCountUtil;
--
--import java.net.SocketAddress;
--import java.util.concurrent.CountDownLatch;
--import java.util.concurrent.TimeUnit;
--import java.util.concurrent.TimeoutException;
--import java.util.concurrent.atomic.AtomicReference;
+-import io.netty.handler.ssl.SslHandshakeCompletionEvent;
+-import io.netty.util.internal.ObjectUtil;
+-import io.netty.util.internal.UnstableApi;
-
-import javax.net.ssl.SSLHandshakeException;
-
--import org.junit.BeforeClass;
--import org.junit.Test;
--
--import static org.junit.Assert.assertArrayEquals;
--import static org.junit.Assert.assertNotNull;
--import static org.junit.Assert.assertNotSame;
--import static org.junit.Assert.assertNull;
--import static org.junit.Assert.assertSame;
--import static org.junit.Assert.assertTrue;
--import static org.junit.Assume.assumeTrue;
--
--public class OcspTest {
--
-- @BeforeClass
-- public static void checkOcspSupported() {
-- assumeTrue(OpenSsl.isOcspSupported());
-- }
--
-- @Test(expected = IllegalArgumentException.class)
-- public void testJdkClientEnableOcsp() throws Exception {
-- SslContextBuilder.forClient()
-- .sslProvider(SslProvider.JDK)
-- .enableOcsp(true)
-- .build();
-- }
--
-- @Test(expected = IllegalArgumentException.class)
-- public void testJdkServerEnableOcsp() throws Exception {
-- SelfSignedCertificate ssc = new SelfSignedCertificate();
-- try {
-- SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey())
-- .sslProvider(SslProvider.JDK)
-- .enableOcsp(true)
-- .build();
-- } finally {
-- ssc.delete();
-- }
-- }
--
-- @Test(expected = IllegalStateException.class)
-- public void testClientOcspNotEnabledOpenSsl() throws Exception {
-- testClientOcspNotEnabled(SslProvider.OPENSSL);
-- }
--
-- @Test(expected = IllegalStateException.class)
-- public void testClientOcspNotEnabledOpenSslRefCnt() throws Exception {
-- testClientOcspNotEnabled(SslProvider.OPENSSL_REFCNT);
-- }
--
-- private void testClientOcspNotEnabled(SslProvider sslProvider) throws Exception {
-- SslContext context = SslContextBuilder.forClient()
-- .sslProvider(sslProvider)
-- .build();
-- try {
-- SslHandler sslHandler = context.newHandler(ByteBufAllocator.DEFAULT);
-- ReferenceCountedOpenSslEngine engine = (ReferenceCountedOpenSslEngine) sslHandler.engine();
-- try {
-- engine.getOcspResponse();
-- } finally {
-- engine.release();
-- }
-- } finally {
-- ReferenceCountUtil.release(context);
-- }
-- }
--
-- @Test(expected = IllegalStateException.class)
-- public void testServerOcspNotEnabledOpenSsl() throws Exception {
-- testServerOcspNotEnabled(SslProvider.OPENSSL);
-- }
--
-- @Test(expected = IllegalStateException.class)
-- public void testServerOcspNotEnabledOpenSslRefCnt() throws Exception {
-- testServerOcspNotEnabled(SslProvider.OPENSSL_REFCNT);
-- }
--
-- private void testServerOcspNotEnabled(SslProvider sslProvider) throws Exception {
-- SelfSignedCertificate ssc = new SelfSignedCertificate();
-- try {
-- SslContext context = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey())
-- .sslProvider(sslProvider)
-- .build();
-- try {
-- SslHandler sslHandler = context.newHandler(ByteBufAllocator.DEFAULT);
-- ReferenceCountedOpenSslEngine engine = (ReferenceCountedOpenSslEngine) sslHandler.engine();
-- try {
-- engine.setOcspResponse(new byte[] { 1, 2, 3 });
-- } finally {
-- engine.release();
-- }
-- } finally {
-- ReferenceCountUtil.release(context);
-- }
-- } finally {
-- ssc.delete();
-- }
-- }
--
-- @Test(timeout = 10000L)
-- public void testClientAcceptingOcspStapleOpenSsl() throws Exception {
-- testClientAcceptingOcspStaple(SslProvider.OPENSSL);
-- }
--
-- @Test(timeout = 10000L)
-- public void testClientAcceptingOcspStapleOpenSslRefCnt() throws Exception {
-- testClientAcceptingOcspStaple(SslProvider.OPENSSL_REFCNT);
-- }
--
-- /**
-- * The Server provides an OCSP staple and the Client accepts it.
-- */
-- private void testClientAcceptingOcspStaple(SslProvider sslProvider) throws Exception {
-- final CountDownLatch latch = new CountDownLatch(1);
-- ChannelInboundHandlerAdapter serverHandler = new ChannelInboundHandlerAdapter() {
-- @Override
-- public void channelActive(ChannelHandlerContext ctx) throws Exception {
-- ctx.writeAndFlush(Unpooled.wrappedBuffer("Hello, World!".getBytes()));
-- ctx.fireChannelActive();
-- }
-- };
--
-- ChannelInboundHandlerAdapter clientHandler = new ChannelInboundHandlerAdapter() {
-- @Override
-- public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
-- try {
-- ReferenceCountUtil.release(msg);
-- } finally {
-- latch.countDown();
-- }
-- }
-- };
--
-- byte[] response = newOcspResponse();
-- TestClientOcspContext callback = new TestClientOcspContext(true);
--
-- handshake(sslProvider, latch, serverHandler, response, clientHandler, callback);
--
-- byte[] actual = callback.response();
--
-- assertNotNull(actual);
-- assertNotSame(response, actual);
-- assertArrayEquals(response, actual);
-- }
--
-- @Test(timeout = 10000L)
-- public void testClientRejectingOcspStapleOpenSsl() throws Exception {
-- testClientRejectingOcspStaple(SslProvider.OPENSSL);
-- }
--
-- @Test(timeout = 10000L)
-- public void testClientRejectingOcspStapleOpenSslRefCnt() throws Exception {
-- testClientRejectingOcspStaple(SslProvider.OPENSSL_REFCNT);
-- }
--
-- /**
-- * The Server provides an OCSP staple and the Client rejects it.
-- */
-- private void testClientRejectingOcspStaple(SslProvider sslProvider) throws Exception {
-- final AtomicReference<Throwable> causeRef = new AtomicReference<Throwable>();
-- final CountDownLatch latch = new CountDownLatch(1);
--
-- ChannelInboundHandlerAdapter clientHandler = new ChannelInboundHandlerAdapter() {
-- @Override
-- public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
-- try {
-- causeRef.set(cause);
-- } finally {
-- latch.countDown();
-- }
-- }
-- };
--
-- byte[] response = newOcspResponse();
-- TestClientOcspContext callback = new TestClientOcspContext(false);
--
-- handshake(sslProvider, latch, null, response, clientHandler, callback);
--
-- byte[] actual = callback.response();
--
-- assertNotNull(actual);
-- assertNotSame(response, actual);
-- assertArrayEquals(response, actual);
--
-- Throwable cause = causeRef.get();
-- assertTrue("" + cause, cause instanceof SSLHandshakeException);
-- }
--
-- @Test(timeout = 10000L)
-- public void testServerHasNoStapleOpenSsl() throws Exception {
-- testServerHasNoStaple(SslProvider.OPENSSL);
-- }
--
-- @Test(timeout = 10000L)
-- public void testServerHasNoStapleOpenSslRefCnt() throws Exception {
-- testServerHasNoStaple(SslProvider.OPENSSL_REFCNT);
-- }
--
-- /**
-- * The server has OCSP stapling enabled but doesn't provide a staple.
-- */
-- private void testServerHasNoStaple(SslProvider sslProvider) throws Exception {
-- final CountDownLatch latch = new CountDownLatch(1);
-- ChannelInboundHandlerAdapter serverHandler = new ChannelInboundHandlerAdapter() {
-- @Override
-- public void channelActive(ChannelHandlerContext ctx) throws Exception {
-- ctx.writeAndFlush(Unpooled.wrappedBuffer("Hello, World!".getBytes()));
-- ctx.fireChannelActive();
-- }
-- };
--
-- ChannelInboundHandlerAdapter clientHandler = new ChannelInboundHandlerAdapter() {
-- @Override
-- public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
-- try {
-- ReferenceCountUtil.release(msg);
-- } finally {
-- latch.countDown();
-- }
-- }
-- };
--
-- byte[] response = null;
-- TestClientOcspContext callback = new TestClientOcspContext(true);
--
-- handshake(sslProvider, latch, serverHandler, response, clientHandler, callback);
--
-- byte[] actual = callback.response();
--
-- assertNull(response);
-- assertNull(actual);
-- }
+-/**
+- * A handler for SSL clients to handle and act upon stapled OCSP responses.
+- *
+- * @see ReferenceCountedOpenSslContext#enableOcsp()
+- * @see ReferenceCountedOpenSslEngine#getOcspResponse()
+- */
+-@UnstableApi
+-public abstract class OcspClientHandler extends ChannelInboundHandlerAdapter {
-
-- @Test(timeout = 10000L)
-- public void testClientExceptionOpenSsl() throws Exception {
-- testClientException(SslProvider.OPENSSL);
-- }
+- private final ReferenceCountedOpenSslEngine engine;
-
-- @Test(timeout = 10000L)
-- public void testClientExceptionOpenSslRefCnt() throws Exception {
-- testClientException(SslProvider.OPENSSL_REFCNT);
+- protected OcspClientHandler(ReferenceCountedOpenSslEngine engine) {
+- this.engine = ObjectUtil.checkNotNull(engine, "engine");
- }
-
- /**
-- * Testing what happens if the {@link OcspClientCallback} throws an {@link Exception}.
-- *
-- * The exception should bubble up on the client side and the connection should get closed.
+- * @see ReferenceCountedOpenSslEngine#getOcspResponse()
- */
-- private void testClientException(SslProvider sslProvider) throws Exception {
-- final AtomicReference<Throwable> causeRef = new AtomicReference<Throwable>();
-- final CountDownLatch latch = new CountDownLatch(1);
--
-- ChannelInboundHandlerAdapter clientHandler = new ChannelInboundHandlerAdapter() {
-- @Override
-- public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
-- try {
-- causeRef.set(cause);
-- } finally {
-- latch.countDown();
-- }
-- }
-- };
--
-- final OcspTestException clientException = new OcspTestException("testClientException");
-- byte[] response = newOcspResponse();
-- OcspClientCallback callback = new OcspClientCallback() {
-- @Override
-- public boolean verify(byte[] response) throws Exception {
-- throw clientException;
-- }
-- };
--
-- handshake(sslProvider, latch, null, response, clientHandler, callback);
--
-- assertSame(clientException, causeRef.get());
-- }
--
-- private static void handshake(SslProvider sslProvider, CountDownLatch latch, ChannelHandler serverHandler,
-- byte[] response, ChannelHandler clientHandler, OcspClientCallback callback) throws Exception {
--
-- SelfSignedCertificate ssc = new SelfSignedCertificate();
-- try {
-- SslContext serverSslContext = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey())
-- .sslProvider(sslProvider)
-- .enableOcsp(true)
-- .build();
--
-- try {
-- SslContext clientSslContext = SslContextBuilder.forClient()
-- .sslProvider(sslProvider)
-- .enableOcsp(true)
-- .trustManager(InsecureTrustManagerFactory.INSTANCE)
-- .build();
--
-- try {
-- EventLoopGroup group = new DefaultEventLoopGroup();
-- try {
-- LocalAddress address = new LocalAddress("handshake-" + Math.random());
-- Channel server = newServer(group, address, serverSslContext, response, serverHandler);
-- Channel client = newClient(group, address, clientSslContext, callback, clientHandler);
-- try {
-- assertTrue("Something went wrong.", latch.await(10L, TimeUnit.SECONDS));
-- } finally {
-- client.close().syncUninterruptibly();
-- server.close().syncUninterruptibly();
-- }
-- } finally {
-- group.shutdownGracefully(1L, 1L, TimeUnit.SECONDS);
-- }
-- } finally {
-- ReferenceCountUtil.release(clientSslContext);
-- }
-- } finally {
-- ReferenceCountUtil.release(serverSslContext);
-- }
-- } finally {
-- ssc.delete();
-- }
-- }
--
-- private static Channel newServer(EventLoopGroup group, SocketAddress address,
-- SslContext context, byte[] response, ChannelHandler handler) {
--
-- ServerBootstrap bootstrap = new ServerBootstrap()
-- .channel(LocalServerChannel.class)
-- .group(group)
-- .childHandler(newServerHandler(context, response, handler));
--
-- return bootstrap.bind(address)
-- .syncUninterruptibly()
-- .channel();
-- }
--
-- private static Channel newClient(EventLoopGroup group, SocketAddress address,
-- SslContext context, OcspClientCallback callback, ChannelHandler handler) {
--
-- Bootstrap bootstrap = new Bootstrap()
-- .channel(LocalChannel.class)
-- .group(group)
-- .handler(newClientHandler(context, callback, handler));
--
-- return bootstrap.connect(address)
-- .syncUninterruptibly()
-- .channel();
-- }
--
-- private static ChannelHandler newServerHandler(final SslContext context,
-- final byte[] response, final ChannelHandler handler) {
-- return new ChannelInitializer<Channel>() {
-- @Override
-- protected void initChannel(Channel ch) throws Exception {
-- ChannelPipeline pipeline = ch.pipeline();
-- SslHandler sslHandler = context.newHandler(ch.alloc());
--
-- if (response != null) {
-- ReferenceCountedOpenSslEngine engine = (ReferenceCountedOpenSslEngine) sslHandler.engine();
-- engine.setOcspResponse(response);
-- }
--
-- pipeline.addLast(sslHandler);
--
-- if (handler != null) {
-- pipeline.addLast(handler);
-- }
-- }
-- };
-- }
--
-- private static ChannelHandler newClientHandler(final SslContext context,
-- final OcspClientCallback callback, final ChannelHandler handler) {
-- return new ChannelInitializer<Channel>() {
-- @Override
-- protected void initChannel(Channel ch) throws Exception {
-- ChannelPipeline pipeline = ch.pipeline();
--
-- SslHandler sslHandler = context.newHandler(ch.alloc());
-- ReferenceCountedOpenSslEngine engine = (ReferenceCountedOpenSslEngine) sslHandler.engine();
+- protected abstract boolean verify(ChannelHandlerContext ctx, ReferenceCountedOpenSslEngine engine) throws Exception;
-
-- pipeline.addLast(sslHandler);
-- pipeline.addLast(new OcspClientCallbackHandler(engine, callback));
+- @Override
+- public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
+- if (evt instanceof SslHandshakeCompletionEvent) {
+- ctx.pipeline().remove(this);
-
-- if (handler != null) {
-- pipeline.addLast(handler);
-- }
+- SslHandshakeCompletionEvent event = (SslHandshakeCompletionEvent) evt;
+- if (event.isSuccess() && !verify(ctx, engine)) {
+- throw new SSLHandshakeException("Bad OCSP response");
- }
-- };
-- }
--
-- private static byte[] newOcspResponse() {
-- // Assume we got the OCSP staple from somewhere. Using a bogus byte[]
-- // in the test because getting a true staple from the CA is quite involved.
-- // It requires HttpCodec and Bouncycastle and the test may be very unreliable
-- // because the OCSP responder servers are basically being DDoS'd by the
-- // Internet.
--
-- return "I am a bogus OCSP staple. OpenSSL does not care about the format of the byte[]!"
-- .getBytes(CharsetUtil.US_ASCII);
-- }
--
-- private interface OcspClientCallback {
-- boolean verify(byte[] staple) throws Exception;
-- }
--
-- private static final class TestClientOcspContext implements OcspClientCallback {
--
-- private final CountDownLatch latch = new CountDownLatch(1);
-- private final boolean valid;
--
-- private volatile byte[] response;
--
-- public TestClientOcspContext(boolean valid) {
-- this.valid = valid;
-- }
--
-- public byte[] response() throws InterruptedException, TimeoutException {
-- assertTrue(latch.await(10L, TimeUnit.SECONDS));
-- return response;
-- }
--
-- @Override
-- public boolean verify(byte[] response) throws Exception {
-- this.response = response;
-- latch.countDown();
--
-- return valid;
-- }
-- }
--
-- private static final class OcspClientCallbackHandler extends OcspClientHandler {
--
-- private final OcspClientCallback callback;
--
-- public OcspClientCallbackHandler(ReferenceCountedOpenSslEngine engine, OcspClientCallback callback) {
-- super(engine);
-- this.callback = callback;
-- }
--
-- @Override
-- protected boolean verify(ChannelHandlerContext ctx, ReferenceCountedOpenSslEngine engine) throws Exception {
-- byte[] response = engine.getOcspResponse();
-- return callback.verify(response);
- }
-- }
-
-- private static final class OcspTestException extends IllegalStateException {
-- public OcspTestException(String message) {
-- super(message);
-- }
+- ctx.fireUserEventTriggered(evt);
- }
-}
+diff --git a/handler/src/main/java/io/netty/handler/ssl/ocsp/package-info.java b/handler/src/main/java/io/netty/handler/ssl/ocsp/package-info.java
+deleted file mode 100644
+index 2883ff48cf..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/ocsp/package-info.java
++++ /dev/null
+@@ -1,23 +0,0 @@
+-/*
+- * Copyright 2017 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- * http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-
+-/**
+- * <a href="https://en.wikipedia.org/wiki/OCSP_stapling">OCSP stapling</a>,
+- * formally known as the TLS Certificate Status Request extension, is an
+- * alternative approach to the Online Certificate Status Protocol (OCSP)
+- * for checking the revocation status of X.509 digital certificates.
+- */
+-package io.netty.handler.ssl.ocsp;
+diff --git a/pom.xml b/pom.xml
+index bedd6d6903..75a2da328a 100644
+--- a/pom.xml
++++ b/pom.xml
+@@ -465,16 +465,6 @@
+ <version>3.0.0-alpha-5</version>
+ </dependency>
+
+- <!-- Our own Tomcat Native fork - completely optional, used for accelerating SSL with OpenSSL. -->
+- <dependency>
+- <groupId>${project.groupId}</groupId>
+- <artifactId>${tcnative.artifactId}</artifactId>
+- <version>${tcnative.version}</version>
+- <classifier>${tcnative.classifier}</classifier>
+- <scope>compile</scope>
+- <optional>true</optional>
+- </dependency>
+-
+ <!--
+ Bouncy Castle - completely optional, only needed when:
+ - you generate a temporary self-signed certificate using SelfSignedCertificate, and
--
-2.9.4
+2.26.2
diff --git a/0005-Remove-optional-dep-log4j.patch b/0005-Remove-optional-dep-log4j.patch
new file mode 100644
index 0000000..9dcd6e7
--- /dev/null
+++ b/0005-Remove-optional-dep-log4j.patch
@@ -0,0 +1,911 @@
+From 1762f36e7ed797747ae692ea2c78001d45b35449 Mon Sep 17 00:00:00 2001
+From: Mat Booth <mat.booth(a)redhat.com>
+Date: Mon, 7 Sep 2020 14:29:44 +0100
+Subject: [PATCH 5/5] Remove optional dep log4j
+
+---
+ common/pom.xml | 15 -
+ .../logging/InternalLoggerFactory.java | 14 +-
+ .../util/internal/logging/Log4J2Logger.java | 143 -----
+ .../internal/logging/Log4J2LoggerFactory.java | 35 -
+ .../util/internal/logging/Log4JLogger.java | 597 ------------------
+ .../internal/logging/Log4JLoggerFactory.java | 40 --
+ 6 files changed, 2 insertions(+), 842 deletions(-)
+ delete mode 100644 common/src/main/java/io/netty/util/internal/logging/Log4J2Logger.java
+ delete mode 100644 common/src/main/java/io/netty/util/internal/logging/Log4J2LoggerFactory.java
+ delete mode 100644 common/src/main/java/io/netty/util/internal/logging/Log4JLogger.java
+ delete mode 100644 common/src/main/java/io/netty/util/internal/logging/Log4JLoggerFactory.java
+
+diff --git a/common/pom.xml b/common/pom.xml
+index abc73161eb..60693fb81a 100644
+--- a/common/pom.xml
++++ b/common/pom.xml
+@@ -63,21 +63,6 @@
+ <artifactId>commons-logging</artifactId>
+ <optional>true</optional>
+ </dependency>
+- <dependency>
+- <groupId>log4j</groupId>
+- <artifactId>log4j</artifactId>
+- <optional>true</optional>
+- </dependency>
+- <dependency>
+- <groupId>org.apache.logging.log4j</groupId>
+- <artifactId>log4j-api</artifactId>
+- <optional>true</optional>
+- </dependency>
+- <dependency>
+- <groupId>org.apache.logging.log4j</groupId>
+- <artifactId>log4j-core</artifactId>
+- <scope>test</scope>
+- </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-core</artifactId>
+diff --git a/common/src/main/java/io/netty/util/internal/logging/InternalLoggerFactory.java b/common/src/main/java/io/netty/util/internal/logging/InternalLoggerFactory.java
+index 508f571820..98eb4e4f4d 100644
+--- a/common/src/main/java/io/netty/util/internal/logging/InternalLoggerFactory.java
++++ b/common/src/main/java/io/netty/util/internal/logging/InternalLoggerFactory.java
+@@ -44,18 +44,8 @@ public abstract class InternalLoggerFactory {
+ f = new Slf4JLoggerFactory(true);
+ f.newInstance(name).debug("Using SLF4J as the default logging framework");
+ } catch (Throwable ignore1) {
+- try {
+- f = Log4J2LoggerFactory.INSTANCE;
+- f.newInstance(name).debug("Using Log4J2 as the default logging framework");
+- } catch (Throwable ignore2) {
+- try {
+- f = Log4JLoggerFactory.INSTANCE;
+- f.newInstance(name).debug("Using Log4J as the default logging framework");
+- } catch (Throwable ignore3) {
+- f = JdkLoggerFactory.INSTANCE;
+- f.newInstance(name).debug("Using java.util.logging as the default logging framework");
+- }
+- }
++ f = JdkLoggerFactory.INSTANCE;
++ f.newInstance(name).debug("Using java.util.logging as the default logging framework");
+ }
+ return f;
+ }
+diff --git a/common/src/main/java/io/netty/util/internal/logging/Log4J2Logger.java b/common/src/main/java/io/netty/util/internal/logging/Log4J2Logger.java
+deleted file mode 100644
+index 5c3593f203..0000000000
+--- a/common/src/main/java/io/netty/util/internal/logging/Log4J2Logger.java
++++ /dev/null
+@@ -1,143 +0,0 @@
+-/*
+- * Copyright 2016 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- * http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-package io.netty.util.internal.logging;
+-
+-
+-import org.apache.logging.log4j.Level;
+-import org.apache.logging.log4j.Logger;
+-import org.apache.logging.log4j.spi.ExtendedLogger;
+-import org.apache.logging.log4j.spi.ExtendedLoggerWrapper;
+-
+-import java.security.AccessController;
+-import java.security.PrivilegedAction;
+-
+-import static io.netty.util.internal.logging.AbstractInternalLogger.EXCEPTION_MESSAGE;
+-
+-class Log4J2Logger extends ExtendedLoggerWrapper implements InternalLogger {
+-
+- private static final long serialVersionUID = 5485418394879791397L;
+- private static final boolean VARARGS_ONLY;
+-
+- static {
+- // Older Log4J2 versions have only log methods that takes the format + varargs. So we should not use
+- // Log4J2 if the version is too old.
+- // See https://github.com/netty/netty/issues/8217
+- VARARGS_ONLY = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
+- @Override
+- public Boolean run() {
+- try {
+- Logger.class.getMethod("debug", String.class, Object.class);
+- return false;
+- } catch (NoSuchMethodException ignore) {
+- // Log4J2 version too old.
+- return true;
+- } catch (SecurityException ignore) {
+- // We could not detect the version so we will use Log4J2 if its on the classpath.
+- return false;
+- }
+- }
+- });
+- }
+-
+- Log4J2Logger(Logger logger) {
+- super((ExtendedLogger) logger, logger.getName(), logger.getMessageFactory());
+- if (VARARGS_ONLY) {
+- throw new UnsupportedOperationException("Log4J2 version mismatch");
+- }
+- }
+-
+- @Override
+- public String name() {
+- return getName();
+- }
+-
+- @Override
+- public void trace(Throwable t) {
+- log(Level.TRACE, EXCEPTION_MESSAGE, t);
+- }
+-
+- @Override
+- public void debug(Throwable t) {
+- log(Level.DEBUG, EXCEPTION_MESSAGE, t);
+- }
+-
+- @Override
+- public void info(Throwable t) {
+- log(Level.INFO, EXCEPTION_MESSAGE, t);
+- }
+-
+- @Override
+- public void warn(Throwable t) {
+- log(Level.WARN, EXCEPTION_MESSAGE, t);
+- }
+-
+- @Override
+- public void error(Throwable t) {
+- log(Level.ERROR, EXCEPTION_MESSAGE, t);
+- }
+-
+- @Override
+- public boolean isEnabled(InternalLogLevel level) {
+- return isEnabled(toLevel(level));
+- }
+-
+- @Override
+- public void log(InternalLogLevel level, String msg) {
+- log(toLevel(level), msg);
+- }
+-
+- @Override
+- public void log(InternalLogLevel level, String format, Object arg) {
+- log(toLevel(level), format, arg);
+- }
+-
+- @Override
+- public void log(InternalLogLevel level, String format, Object argA, Object argB) {
+- log(toLevel(level), format, argA, argB);
+- }
+-
+- @Override
+- public void log(InternalLogLevel level, String format, Object... arguments) {
+- log(toLevel(level), format, arguments);
+- }
+-
+- @Override
+- public void log(InternalLogLevel level, String msg, Throwable t) {
+- log(toLevel(level), msg, t);
+- }
+-
+- @Override
+- public void log(InternalLogLevel level, Throwable t) {
+- log(toLevel(level), EXCEPTION_MESSAGE, t);
+- }
+-
+- private static Level toLevel(InternalLogLevel level) {
+- switch (level) {
+- case INFO:
+- return Level.INFO;
+- case DEBUG:
+- return Level.DEBUG;
+- case WARN:
+- return Level.WARN;
+- case ERROR:
+- return Level.ERROR;
+- case TRACE:
+- return Level.TRACE;
+- default:
+- throw new Error();
+- }
+- }
+-}
+diff --git a/common/src/main/java/io/netty/util/internal/logging/Log4J2LoggerFactory.java b/common/src/main/java/io/netty/util/internal/logging/Log4J2LoggerFactory.java
+deleted file mode 100644
+index 8b895fbc07..0000000000
+--- a/common/src/main/java/io/netty/util/internal/logging/Log4J2LoggerFactory.java
++++ /dev/null
+@@ -1,35 +0,0 @@
+-/*
+- * Copyright 2016 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- * http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-package io.netty.util.internal.logging;
+-
+-import org.apache.logging.log4j.LogManager;
+-
+-public final class Log4J2LoggerFactory extends InternalLoggerFactory {
+-
+- public static final InternalLoggerFactory INSTANCE = new Log4J2LoggerFactory();
+-
+- /**
+- * @deprecated Use {@link #INSTANCE} instead.
+- */
+- @Deprecated
+- public Log4J2LoggerFactory() {
+- }
+-
+- @Override
+- public InternalLogger newInstance(String name) {
+- return new Log4J2Logger(LogManager.getLogger(name));
+- }
+-}
+diff --git a/common/src/main/java/io/netty/util/internal/logging/Log4JLogger.java b/common/src/main/java/io/netty/util/internal/logging/Log4JLogger.java
+deleted file mode 100644
+index 27b9130a08..0000000000
+--- a/common/src/main/java/io/netty/util/internal/logging/Log4JLogger.java
++++ /dev/null
+@@ -1,597 +0,0 @@
+-/*
+- * Copyright 2012 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- * http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-/**
+- * Copyright (c) 2004-2011 QOS.ch
+- * All rights reserved.
+- *
+- * Permission is hereby granted, free of charge, to any person obtaining
+- * a copy of this software and associated documentation files (the
+- * "Software"), to deal in the Software without restriction, including
+- * without limitation the rights to use, copy, modify, merge, publish,
+- * distribute, sublicense, and/or sell copies of the Software, and to
+- * permit persons to whom the Software is furnished to do so, subject to
+- * the following conditions:
+- *
+- * The above copyright notice and this permission notice shall be
+- * included in all copies or substantial portions of the Software.
+- *
+- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+- *
+- */
+-package io.netty.util.internal.logging;
+-
+-import org.apache.log4j.Level;
+-import org.apache.log4j.Logger;
+-
+-/**
+- * <a href="http://logging.apache.org/log4j/1.2/index.html">Apache Log4J</a>
+- * logger.
+- */
+-class Log4JLogger extends AbstractInternalLogger {
+-
+- private static final long serialVersionUID = 2851357342488183058L;
+-
+- final transient Logger logger;
+-
+- /**
+- * Following the pattern discussed in pages 162 through 168 of "The complete
+- * log4j manual".
+- */
+- static final String FQCN = Log4JLogger.class.getName();
+-
+- // Does the log4j version in use recognize the TRACE level?
+- // The trace level was introduced in log4j 1.2.12.
+- final boolean traceCapable;
+-
+- Log4JLogger(Logger logger) {
+- super(logger.getName());
+- this.logger = logger;
+- traceCapable = isTraceCapable();
+- }
+-
+- private boolean isTraceCapable() {
+- try {
+- logger.isTraceEnabled();
+- return true;
+- } catch (NoSuchMethodError ignored) {
+- return false;
+- }
+- }
+-
+- /**
+- * Is this logger instance enabled for the TRACE level?
+- *
+- * @return True if this Logger is enabled for level TRACE, false otherwise.
+- */
+- @Override
+- public boolean isTraceEnabled() {
+- if (traceCapable) {
+- return logger.isTraceEnabled();
+- } else {
+- return logger.isDebugEnabled();
+- }
+- }
+-
+- /**
+- * Log a message object at level TRACE.
+- *
+- * @param msg
+- * - the message object to be logged
+- */
+- @Override
+- public void trace(String msg) {
+- logger.log(FQCN, traceCapable ? Level.TRACE : Level.DEBUG, msg, null);
+- }
+-
+- /**
+- * Log a message at level TRACE according to the specified format and
+- * argument.
+- *
+- * <p>
+- * This form avoids superfluous object creation when the logger is disabled
+- * for level TRACE.
+- * </p>
+- *
+- * @param format
+- * the format string
+- * @param arg
+- * the argument
+- */
+- @Override
+- public void trace(String format, Object arg) {
+- if (isTraceEnabled()) {
+- FormattingTuple ft = MessageFormatter.format(format, arg);
+- logger.log(FQCN, traceCapable ? Level.TRACE : Level.DEBUG, ft
+- .getMessage(), ft.getThrowable());
+- }
+- }
+-
+- /**
+- * Log a message at level TRACE according to the specified format and
+- * arguments.
+- *
+- * <p>
+- * This form avoids superfluous object creation when the logger is disabled
+- * for the TRACE level.
+- * </p>
+- *
+- * @param format
+- * the format string
+- * @param argA
+- * the first argument
+- * @param argB
+- * the second argument
+- */
+- @Override
+- public void trace(String format, Object argA, Object argB) {
+- if (isTraceEnabled()) {
+- FormattingTuple ft = MessageFormatter.format(format, argA, argB);
+- logger.log(FQCN, traceCapable ? Level.TRACE : Level.DEBUG, ft
+- .getMessage(), ft.getThrowable());
+- }
+- }
+-
+- /**
+- * Log a message at level TRACE according to the specified format and
+- * arguments.
+- *
+- * <p>
+- * This form avoids superfluous object creation when the logger is disabled
+- * for the TRACE level.
+- * </p>
+- *
+- * @param format
+- * the format string
+- * @param arguments
+- * an array of arguments
+- */
+- @Override
+- public void trace(String format, Object... arguments) {
+- if (isTraceEnabled()) {
+- FormattingTuple ft = MessageFormatter.arrayFormat(format, arguments);
+- logger.log(FQCN, traceCapable ? Level.TRACE : Level.DEBUG, ft
+- .getMessage(), ft.getThrowable());
+- }
+- }
+-
+- /**
+- * Log an exception (throwable) at level TRACE with an accompanying message.
+- *
+- * @param msg
+- * the message accompanying the exception
+- * @param t
+- * the exception (throwable) to log
+- */
+- @Override
+- public void trace(String msg, Throwable t) {
+- logger.log(FQCN, traceCapable ? Level.TRACE : Level.DEBUG, msg, t);
+- }
+-
+- /**
+- * Is this logger instance enabled for the DEBUG level?
+- *
+- * @return True if this Logger is enabled for level DEBUG, false otherwise.
+- */
+- @Override
+- public boolean isDebugEnabled() {
+- return logger.isDebugEnabled();
+- }
+-
+- /**
+- * Log a message object at level DEBUG.
+- *
+- * @param msg
+- * - the message object to be logged
+- */
+- @Override
+- public void debug(String msg) {
+- logger.log(FQCN, Level.DEBUG, msg, null);
+- }
+-
+- /**
+- * Log a message at level DEBUG according to the specified format and
+- * argument.
+- *
+- * <p>
+- * This form avoids superfluous object creation when the logger is disabled
+- * for level DEBUG.
+- * </p>
+- *
+- * @param format
+- * the format string
+- * @param arg
+- * the argument
+- */
+- @Override
+- public void debug(String format, Object arg) {
+- if (logger.isDebugEnabled()) {
+- FormattingTuple ft = MessageFormatter.format(format, arg);
+- logger.log(FQCN, Level.DEBUG, ft.getMessage(), ft.getThrowable());
+- }
+- }
+-
+- /**
+- * Log a message at level DEBUG according to the specified format and
+- * arguments.
+- *
+- * <p>
+- * This form avoids superfluous object creation when the logger is disabled
+- * for the DEBUG level.
+- * </p>
+- *
+- * @param format
+- * the format string
+- * @param argA
+- * the first argument
+- * @param argB
+- * the second argument
+- */
+- @Override
+- public void debug(String format, Object argA, Object argB) {
+- if (logger.isDebugEnabled()) {
+- FormattingTuple ft = MessageFormatter.format(format, argA, argB);
+- logger.log(FQCN, Level.DEBUG, ft.getMessage(), ft.getThrowable());
+- }
+- }
+-
+- /**
+- * Log a message at level DEBUG according to the specified format and
+- * arguments.
+- *
+- * <p>
+- * This form avoids superfluous object creation when the logger is disabled
+- * for the DEBUG level.
+- * </p>
+- *
+- * @param format
+- * the format string
+- * @param arguments an array of arguments
+- */
+- @Override
+- public void debug(String format, Object... arguments) {
+- if (logger.isDebugEnabled()) {
+- FormattingTuple ft = MessageFormatter.arrayFormat(format, arguments);
+- logger.log(FQCN, Level.DEBUG, ft.getMessage(), ft.getThrowable());
+- }
+- }
+-
+- /**
+- * Log an exception (throwable) at level DEBUG with an accompanying message.
+- *
+- * @param msg
+- * the message accompanying the exception
+- * @param t
+- * the exception (throwable) to log
+- */
+- @Override
+- public void debug(String msg, Throwable t) {
+- logger.log(FQCN, Level.DEBUG, msg, t);
+- }
+-
+- /**
+- * Is this logger instance enabled for the INFO level?
+- *
+- * @return True if this Logger is enabled for the INFO level, false otherwise.
+- */
+- @Override
+- public boolean isInfoEnabled() {
+- return logger.isInfoEnabled();
+- }
+-
+- /**
+- * Log a message object at the INFO level.
+- *
+- * @param msg
+- * - the message object to be logged
+- */
+- @Override
+- public void info(String msg) {
+- logger.log(FQCN, Level.INFO, msg, null);
+- }
+-
+- /**
+- * Log a message at level INFO according to the specified format and argument.
+- *
+- * <p>
+- * This form avoids superfluous object creation when the logger is disabled
+- * for the INFO level.
+- * </p>
+- *
+- * @param format
+- * the format string
+- * @param arg
+- * the argument
+- */
+- @Override
+- public void info(String format, Object arg) {
+- if (logger.isInfoEnabled()) {
+- FormattingTuple ft = MessageFormatter.format(format, arg);
+- logger.log(FQCN, Level.INFO, ft.getMessage(), ft.getThrowable());
+- }
+- }
+-
+- /**
+- * Log a message at the INFO level according to the specified format and
+- * arguments.
+- *
+- * <p>
+- * This form avoids superfluous object creation when the logger is disabled
+- * for the INFO level.
+- * </p>
+- *
+- * @param format
+- * the format string
+- * @param argA
+- * the first argument
+- * @param argB
+- * the second argument
+- */
+- @Override
+- public void info(String format, Object argA, Object argB) {
+- if (logger.isInfoEnabled()) {
+- FormattingTuple ft = MessageFormatter.format(format, argA, argB);
+- logger.log(FQCN, Level.INFO, ft.getMessage(), ft.getThrowable());
+- }
+- }
+-
+- /**
+- * Log a message at level INFO according to the specified format and
+- * arguments.
+- *
+- * <p>
+- * This form avoids superfluous object creation when the logger is disabled
+- * for the INFO level.
+- * </p>
+- *
+- * @param format
+- * the format string
+- * @param argArray
+- * an array of arguments
+- */
+- @Override
+- public void info(String format, Object... argArray) {
+- if (logger.isInfoEnabled()) {
+- FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray);
+- logger.log(FQCN, Level.INFO, ft.getMessage(), ft.getThrowable());
+- }
+- }
+-
+- /**
+- * Log an exception (throwable) at the INFO level with an accompanying
+- * message.
+- *
+- * @param msg
+- * the message accompanying the exception
+- * @param t
+- * the exception (throwable) to log
+- */
+- @Override
+- public void info(String msg, Throwable t) {
+- logger.log(FQCN, Level.INFO, msg, t);
+- }
+-
+- /**
+- * Is this logger instance enabled for the WARN level?
+- *
+- * @return True if this Logger is enabled for the WARN level, false otherwise.
+- */
+- @Override
+- public boolean isWarnEnabled() {
+- return logger.isEnabledFor(Level.WARN);
+- }
+-
+- /**
+- * Log a message object at the WARN level.
+- *
+- * @param msg
+- * - the message object to be logged
+- */
+- @Override
+- public void warn(String msg) {
+- logger.log(FQCN, Level.WARN, msg, null);
+- }
+-
+- /**
+- * Log a message at the WARN level according to the specified format and
+- * argument.
+- *
+- * <p>
+- * This form avoids superfluous object creation when the logger is disabled
+- * for the WARN level.
+- * </p>
+- *
+- * @param format
+- * the format string
+- * @param arg
+- * the argument
+- */
+- @Override
+- public void warn(String format, Object arg) {
+- if (logger.isEnabledFor(Level.WARN)) {
+- FormattingTuple ft = MessageFormatter.format(format, arg);
+- logger.log(FQCN, Level.WARN, ft.getMessage(), ft.getThrowable());
+- }
+- }
+-
+- /**
+- * Log a message at the WARN level according to the specified format and
+- * arguments.
+- *
+- * <p>
+- * This form avoids superfluous object creation when the logger is disabled
+- * for the WARN level.
+- * </p>
+- *
+- * @param format
+- * the format string
+- * @param argA
+- * the first argument
+- * @param argB
+- * the second argument
+- */
+- @Override
+- public void warn(String format, Object argA, Object argB) {
+- if (logger.isEnabledFor(Level.WARN)) {
+- FormattingTuple ft = MessageFormatter.format(format, argA, argB);
+- logger.log(FQCN, Level.WARN, ft.getMessage(), ft.getThrowable());
+- }
+- }
+-
+- /**
+- * Log a message at level WARN according to the specified format and
+- * arguments.
+- *
+- * <p>
+- * This form avoids superfluous object creation when the logger is disabled
+- * for the WARN level.
+- * </p>
+- *
+- * @param format
+- * the format string
+- * @param argArray
+- * an array of arguments
+- */
+- @Override
+- public void warn(String format, Object... argArray) {
+- if (logger.isEnabledFor(Level.WARN)) {
+- FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray);
+- logger.log(FQCN, Level.WARN, ft.getMessage(), ft.getThrowable());
+- }
+- }
+-
+- /**
+- * Log an exception (throwable) at the WARN level with an accompanying
+- * message.
+- *
+- * @param msg
+- * the message accompanying the exception
+- * @param t
+- * the exception (throwable) to log
+- */
+- @Override
+- public void warn(String msg, Throwable t) {
+- logger.log(FQCN, Level.WARN, msg, t);
+- }
+-
+- /**
+- * Is this logger instance enabled for level ERROR?
+- *
+- * @return True if this Logger is enabled for level ERROR, false otherwise.
+- */
+- @Override
+- public boolean isErrorEnabled() {
+- return logger.isEnabledFor(Level.ERROR);
+- }
+-
+- /**
+- * Log a message object at the ERROR level.
+- *
+- * @param msg
+- * - the message object to be logged
+- */
+- @Override
+- public void error(String msg) {
+- logger.log(FQCN, Level.ERROR, msg, null);
+- }
+-
+- /**
+- * Log a message at the ERROR level according to the specified format and
+- * argument.
+- *
+- * <p>
+- * This form avoids superfluous object creation when the logger is disabled
+- * for the ERROR level.
+- * </p>
+- *
+- * @param format
+- * the format string
+- * @param arg
+- * the argument
+- */
+- @Override
+- public void error(String format, Object arg) {
+- if (logger.isEnabledFor(Level.ERROR)) {
+- FormattingTuple ft = MessageFormatter.format(format, arg);
+- logger.log(FQCN, Level.ERROR, ft.getMessage(), ft.getThrowable());
+- }
+- }
+-
+- /**
+- * Log a message at the ERROR level according to the specified format and
+- * arguments.
+- *
+- * <p>
+- * This form avoids superfluous object creation when the logger is disabled
+- * for the ERROR level.
+- * </p>
+- *
+- * @param format
+- * the format string
+- * @param argA
+- * the first argument
+- * @param argB
+- * the second argument
+- */
+- @Override
+- public void error(String format, Object argA, Object argB) {
+- if (logger.isEnabledFor(Level.ERROR)) {
+- FormattingTuple ft = MessageFormatter.format(format, argA, argB);
+- logger.log(FQCN, Level.ERROR, ft.getMessage(), ft.getThrowable());
+- }
+- }
+-
+- /**
+- * Log a message at level ERROR according to the specified format and
+- * arguments.
+- *
+- * <p>
+- * This form avoids superfluous object creation when the logger is disabled
+- * for the ERROR level.
+- * </p>
+- *
+- * @param format
+- * the format string
+- * @param argArray
+- * an array of arguments
+- */
+- @Override
+- public void error(String format, Object... argArray) {
+- if (logger.isEnabledFor(Level.ERROR)) {
+- FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray);
+- logger.log(FQCN, Level.ERROR, ft.getMessage(), ft.getThrowable());
+- }
+- }
+-
+- /**
+- * Log an exception (throwable) at the ERROR level with an accompanying
+- * message.
+- *
+- * @param msg
+- * the message accompanying the exception
+- * @param t
+- * the exception (throwable) to log
+- */
+- @Override
+- public void error(String msg, Throwable t) {
+- logger.log(FQCN, Level.ERROR, msg, t);
+- }
+-}
+diff --git a/common/src/main/java/io/netty/util/internal/logging/Log4JLoggerFactory.java b/common/src/main/java/io/netty/util/internal/logging/Log4JLoggerFactory.java
+deleted file mode 100644
+index 399a279df3..0000000000
+--- a/common/src/main/java/io/netty/util/internal/logging/Log4JLoggerFactory.java
++++ /dev/null
+@@ -1,40 +0,0 @@
+-/*
+- * Copyright 2012 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- * http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-package io.netty.util.internal.logging;
+-
+-import org.apache.log4j.Logger;
+-
+-/**
+- * Logger factory which creates an
+- * <a href="http://logging.apache.org/log4j/1.2/index.html">Apache Log4J</a>
+- * logger.
+- */
+-public class Log4JLoggerFactory extends InternalLoggerFactory {
+-
+- public static final InternalLoggerFactory INSTANCE = new Log4JLoggerFactory();
+-
+- /**
+- * @deprecated Use {@link #INSTANCE} instead.
+- */
+- @Deprecated
+- public Log4JLoggerFactory() {
+- }
+-
+- @Override
+- public InternalLogger newInstance(String name) {
+- return new Log4JLogger(Logger.getLogger(name));
+- }
+-}
+--
+2.26.2
+
diff --git a/netty.spec b/netty.spec
index 5a630f0..90e1234 100644
--- a/netty.spec
+++ b/netty.spec
@@ -1,13 +1,9 @@
-# Disable generation of debuginfo package
-%global debug_package %{nil}
%global namedreltag .Final
%global namedversion %{version}%{?namedreltag}
-%bcond_without jp_minimal
-
Name: netty
-Version: 4.1.13
-Release: 19%{?dist}
+Version: 4.1.51
+Release: 1%{?dist}
Summary: An asynchronous event-driven network application framework and tools for Java
License: ASL 2.0
URL: https://netty.io/
@@ -16,42 +12,25 @@ Source0: https://github.com/netty/netty/archive/netty-%{namedversion}.tar
# We don't have the plugin and want to avoid groovy dependency
# This script is written in bash+sed and performs the same task
Source1: codegen.bash
-Patch0: 0001-Remove-OpenSSL-parts-depending-on-tcnative.patch
-Patch1: 0002-Remove-NPN.patch
-Patch2: 0003-Remove-conscrypt-ALPN.patch
-Patch3: 0004-Remove-jetty-ALPN.patch
+Patch0: 0001-Remove-optional-dep-Blockhound.patch
+Patch1: 0002-Remove-optional-dep-conscrypt.patch
+Patch2: 0003-Remove-optional-deps-jetty-alpn-and-npn.patch
+Patch3: 0004-Remove-optional-dep-tcnative.patch
+Patch4: 0005-Remove-optional-dep-log4j.patch
BuildRequires: maven-local
-BuildRequires: mvn(ant-contrib:ant-contrib)
BuildRequires: mvn(com.jcraft:jzlib)
BuildRequires: mvn(commons-logging:commons-logging)
BuildRequires: mvn(kr.motd.maven:os-maven-plugin)
-BuildRequires: mvn(log4j:log4j:1.2.17)
BuildRequires: mvn(org.apache.felix:maven-bundle-plugin)
-BuildRequires: mvn(org.apache.maven.plugins:maven-antrun-plugin)
-BuildRequires: mvn(org.apache.maven.plugins:maven-dependency-plugin)
BuildRequires: mvn(org.apache.maven.plugins:maven-remote-resources-plugin)
+BuildRequires: mvn(org.bouncycastle:bcpkix-jdk15on)
BuildRequires: mvn(org.codehaus.mojo:build-helper-maven-plugin)
BuildRequires: mvn(org.codehaus.mojo:exec-maven-plugin)
-BuildRequires: mvn(org.fusesource.hawtjni:maven-hawtjni-plugin)
BuildRequires: mvn(org.jctools:jctools-core)
BuildRequires: mvn(org.slf4j:slf4j-api)
-%if %{without jp_minimal}
-BuildRequires: mvn(com.fasterxml:aalto-xml)
-BuildRequires: mvn(com.github.jponge:lzma-java)
-BuildRequires: mvn(com.ning:compress-lzf)
-BuildRequires: mvn(net.jpountz.lz4:lz4)
-BuildRequires: mvn(org.apache.logging.log4j:log4j-api)
-BuildRequires: mvn(org.bouncycastle:bcpkix-jdk15on)
-BuildRequires: mvn(org.jboss.marshalling:jboss-marshalling)
-BuildRequires: mvn(org.eclipse.jetty.alpn:alpn-api)
-%endif
-%ifarch %{arm}
-# Speed up builds on 32bit arm
-# Disable temporarily due to https://bugzilla.redhat.com/show_bug.cgi?id=1818078
-#BuildRequires: java-1.8.0-openjdk-aarch32-devel
-%endif
+BuildArch: noarch
%description
Netty is a NIO client server framework which enables quick and easy
@@ -79,9 +58,8 @@ Summary: API documentation for %{name}
%patch0 -p1
%patch1 -p1
%patch2 -p1
-%if %{with jp_minimal}
%patch3 -p1
-%endif
+%patch4 -p1
# remove unnecessary dependency on parent POM
%pom_remove_parent . bom dev-tools
@@ -89,15 +67,8 @@ Summary: API documentation for %{name}
# Disable all in one jar
%pom_disable_module all
-# Missing Mavenized rxtx
-%pom_disable_module "transport-rxtx"
-# Missing com.barchart.udt:barchart-udt-bundle:jar:2.3.0
-%pom_disable_module "transport-udt"
-# Not needed
+# Not needed for RPM builds
%pom_disable_module "example"
-%pom_disable_module "testsuite"
-%pom_disable_module "testsuite-autobahn"
-%pom_disable_module "testsuite-osgi"
%pom_disable_module "tarball"
%pom_disable_module "microbench"
@@ -112,7 +83,6 @@ Summary: API documentation for %{name}
%pom_remove_plugin :maven-antrun-plugin
%pom_remove_plugin :maven-dependency-plugin
-# style checker
%pom_remove_plugin :xml-maven-plugin
%pom_remove_plugin -r :maven-checkstyle-plugin
%pom_remove_plugin -r :animal-sniffer-maven-plugin
@@ -143,6 +113,10 @@ cp %{SOURCE1} common/codegen.bash
'
%pom_remove_plugin :groovy-maven-plugin common
+# We don't have com.oracle.substratevm
+%pom_remove_dep "com.oracle.substratevm:" common
+rm common/src/main/java/io/netty/util/internal/svm/*
+
# The protobuf-javanano API was discontinued upstream and obsoleted in Fedora
# so disable support for protobuf in the codecs module
%pom_remove_dep -r "com.google.protobuf:protobuf-java"
@@ -150,31 +124,41 @@ cp %{SOURCE1} common/codegen.bash
rm codec/src/main/java/io/netty/handler/codec/protobuf/*
sed -i '/import.*protobuf/d' codec/src/main/java/io/netty/handler/codec/DatagramPacket*.java
-%if %{with jp_minimal}
+# JBoss marshalling not available in Fedora
%pom_remove_dep -r "org.jboss.marshalling:jboss-marshalling"
rm codec/src/main/java/io/netty/handler/codec/marshalling/*
-%pom_remove_dep -r org.bouncycastle
-rm handler/src/main/java/io/netty/handler/ssl/util/BouncyCastleSelfSignedCertGenerator.java
-sed -i '/BouncyCastleSelfSignedCertGenerator/s/.*/throw new UnsupportedOperationException();/' \
- handler/src/main/java/io/netty/handler/ssl/util/SelfSignedCertificate.java
-%pom_remove_dep -r com.fasterxml:aalto-xml
-%pom_disable_module codec-xml
+
+# Various compression codecs not available in Fedora
%pom_remove_dep -r com.github.jponge:lzma-java
rm codec/src/*/java/io/netty/handler/codec/compression/Lzma*.java
%pom_remove_dep -r com.ning:compress-lzf
rm codec/src/*/java/io/netty/handler/codec/compression/Lzf*.java
%pom_remove_dep -r net.jpountz.lz4:lz4
rm codec/src/*/java/io/netty/handler/codec/compression/Lz4*.java
-%pom_remove_dep -r org.apache.logging.log4j:
-rm common/*/main/java/io/netty/util/internal/logging/Log4J2*.java
-# Disable rarely needed native artifacts
+# Disable other codecs with extra dependencies
+%pom_remove_dep -r com.fasterxml:aalto-xml
+%pom_disable_module codec-xml
+
+# Disable unneeded transport artifacts
%pom_disable_module transport-native-epoll
%pom_disable_module transport-native-kqueue
-
-%endif
-
-%pom_xpath_inject "pom:execution[pom:id = 'build-native-lib']/pom:configuration" '<verbose>true</verbose>' transport-native-epoll/pom.xml
+%pom_disable_module transport-native-unix-common
+%pom_disable_module transport-rxtx
+%pom_disable_module transport-sctp
+%pom_disable_module transport-udt
+
+# Disable macos native bit
+%pom_disable_module resolver-dns-native-macos
+
+# Disable test suites
+%pom_disable_module testsuite
+%pom_disable_module testsuite-autobahn
+%pom_disable_module testsuite-http2
+%pom_disable_module testsuite-native-image
+%pom_disable_module testsuite-osgi
+%pom_disable_module testsuite-shading
+%pom_disable_module transport-native-unix-common-tests
# Upstream has jctools bundled.
%pom_xpath_remove "pom:build/pom:plugins/pom:plugin[pom:artifactId = 'maven-bundle-plugin']/pom:executions/pom:execution[pom:id = 'generate-manifest']/pom:configuration/pom:instructions/pom:Import-Package" common/pom.xml
@@ -184,11 +168,7 @@ rm common/*/main/java/io/netty/util/internal/logging/Log4J2*.java
# the linux classifier.
%mvn_package ":::linux*:"
-%mvn_package ':*-tests' __noinstall
-
%build
-export JAVA_HOME=%{_jvmdir}/java
-
# Ensure we use distro compile flags
export CFLAGS="$RPM_OPT_FLAGS" LDFLAGS="$RPM_LD_FLAGS"
@@ -204,6 +184,10 @@ export CFLAGS="$RPM_OPT_FLAGS" LDFLAGS="$RPM_LD_FLAGS"
%license LICENSE.txt NOTICE.txt
%changelog
+* Mon Sep 07 2020 Mat Booth <mat.booth(a)redhat.com> - 4.1.51-1
+- Update to latest upstream version
+- Native bits were not used by anything, so package is now noarch
+
* Tue Jul 28 2020 Fedora Release Engineering <releng(a)fedoraproject.org> - 4.1.13-19
- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild
diff --git a/sources b/sources
index 39533ac..a39ea3d 100644
--- a/sources
+++ b/sources
@@ -1 +1 @@
-SHA512 (netty-4.1.13.Final.tar.gz) = f0a269adf5b6552eb2f0f12614c2093e0ccfd5a5bb38521dcf39c3827160c8983adcfe1bbcf93a24e71506e323ae723a837621046657fec0df50c59a07aee54c
+SHA512 (netty-4.1.51.Final.tar.gz) = 3b6e00b48710ada4e2c3fbcd71a2c82804dded30c8fa99f10dc609e063642ab5351fe0c26183b03a429439d2351b51ca4cfe803e68dfc5929156faafb1a47800
3 years, 8 months
Architecture specific change in rpms/netty.git
by githook-noreply@fedoraproject.org
The package rpms/netty.git has added or updated architecture specific content in its
spec file (ExclusiveArch/ExcludeArch or %ifarch/%ifnarch) in commit(s):
https://src.fedoraproject.org/cgit/rpms/netty.git/commit/?id=342e6b392cd9....
Change:
-%ifarch %{arm}
Thanks.
Full change:
============
commit 342e6b392cd905be34a8918ca862d2dca9a3dcd8
Author: Mat Booth <mat.booth(a)redhat.com>
Date: Mon Sep 7 14:53:52 2020 +0100
Update to latest upstream version
Native bits were not used by anything, so package is now noarch
diff --git a/.gitignore b/.gitignore
index 859e799..488860d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,2 @@
-/netty-4.0.42.Final.tar.gz
-/netty-4.1.13.Final.tar.gz
+/netty-*.tar.gz
+/*.src.rpm
diff --git a/0001-Remove-optional-dep-Blockhound.patch b/0001-Remove-optional-dep-Blockhound.patch
new file mode 100644
index 0000000..783b2f8
--- /dev/null
+++ b/0001-Remove-optional-dep-Blockhound.patch
@@ -0,0 +1,633 @@
+From 14fa8d4afda0fa1a31a2591298dc5c18e08dab1f Mon Sep 17 00:00:00 2001
+From: Mat Booth <mat.booth(a)redhat.com>
+Date: Mon, 7 Sep 2020 12:17:31 +0100
+Subject: [PATCH 1/5] Remove optional dep Blockhound
+
+---
+ common/pom.xml | 5 -
+ .../java/io/netty/util/internal/Hidden.java | 113 ---------
+ ...ockhound.integration.BlockHoundIntegration | 14 -
+ pom.xml | 7 -
+ transport-blockhound-tests/pom.xml | 92 -------
+ .../NettyBlockHoundIntegrationTest.java | 239 ------------------
+ .../netty/util/internal/localhost_server.key | 28 --
+ .../netty/util/internal/localhost_server.pem | 17 --
+ .../io/netty/util/internal/mutual_auth_ca.pem | 19 --
+ 9 files changed, 534 deletions(-)
+ delete mode 100644 common/src/main/java/io/netty/util/internal/Hidden.java
+ delete mode 100644 common/src/main/resources/META-INF/services/reactor.blockhound.integration.BlockHoundIntegration
+ delete mode 100644 transport-blockhound-tests/pom.xml
+ delete mode 100644 transport-blockhound-tests/src/test/java/io/netty/util/internal/NettyBlockHoundIntegrationTest.java
+ delete mode 100644 transport-blockhound-tests/src/test/resources/io/netty/util/internal/localhost_server.key
+ delete mode 100644 transport-blockhound-tests/src/test/resources/io/netty/util/internal/localhost_server.pem
+ delete mode 100644 transport-blockhound-tests/src/test/resources/io/netty/util/internal/mutual_auth_ca.pem
+
+diff --git a/common/pom.xml b/common/pom.xml
+index 706279177a..abc73161eb 100644
+--- a/common/pom.xml
++++ b/common/pom.xml
+@@ -78,11 +78,6 @@
+ <artifactId>log4j-core</artifactId>
+ <scope>test</scope>
+ </dependency>
+- <dependency>
+- <groupId>io.projectreactor.tools</groupId>
+- <artifactId>blockhound</artifactId>
+- <optional>true</optional>
+- </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-core</artifactId>
+diff --git a/common/src/main/java/io/netty/util/internal/Hidden.java b/common/src/main/java/io/netty/util/internal/Hidden.java
+deleted file mode 100644
+index 7fd6d08396..0000000000
+--- a/common/src/main/java/io/netty/util/internal/Hidden.java
++++ /dev/null
+@@ -1,113 +0,0 @@
+-/*
+- * Copyright 2019 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- * http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-
+-package io.netty.util.internal;
+-
+-import io.netty.util.concurrent.FastThreadLocalThread;
+-import reactor.blockhound.BlockHound;
+-import reactor.blockhound.integration.BlockHoundIntegration;
+-
+-import java.util.function.Function;
+-import java.util.function.Predicate;
+-
+-/**
+- * Contains classes that must be have public visibility but are not public API.
+- */
+-class Hidden {
+-
+- /**
+- * This class integrates Netty with BlockHound.
+- * <p>
+- * It is public but only because of the ServiceLoader's limitations
+- * and SHOULD NOT be considered a public API.
+- */
+- @UnstableApi
+- @SuppressJava6Requirement(reason = "BlockHound is Java 8+, but this class is only loaded by it's SPI")
+- public static final class NettyBlockHoundIntegration implements BlockHoundIntegration {
+-
+- @Override
+- public void applyTo(BlockHound.Builder builder) {
+- builder.allowBlockingCallsInside(
+- "io.netty.channel.nio.NioEventLoop",
+- "handleLoopException"
+- );
+-
+- builder.allowBlockingCallsInside(
+- "io.netty.channel.kqueue.KQueueEventLoop",
+- "handleLoopException"
+- );
+-
+- builder.allowBlockingCallsInside(
+- "io.netty.channel.epoll.EpollEventLoop",
+- "handleLoopException"
+- );
+-
+- builder.allowBlockingCallsInside(
+- "io.netty.util.HashedWheelTimer$Worker",
+- "waitForNextTick"
+- );
+-
+- builder.allowBlockingCallsInside(
+- "io.netty.util.concurrent.SingleThreadEventExecutor",
+- "confirmShutdown"
+- );
+-
+- builder.allowBlockingCallsInside(
+- "io.netty.handler.ssl.SslHandler",
+- "handshake"
+- );
+-
+- builder.allowBlockingCallsInside(
+- "io.netty.handler.ssl.SslHandler",
+- "runAllDelegatedTasks"
+- );
+-
+- builder.allowBlockingCallsInside(
+- "io.netty.util.concurrent.GlobalEventExecutor",
+- "takeTask");
+-
+- builder.allowBlockingCallsInside(
+- "io.netty.util.concurrent.GlobalEventExecutor",
+- "addTask");
+-
+- builder.allowBlockingCallsInside(
+- "io.netty.util.concurrent.SingleThreadEventExecutor",
+- "takeTask");
+-
+- builder.allowBlockingCallsInside(
+- "io.netty.handler.ssl.ReferenceCountedOpenSslClientContext$ExtendedTrustManagerVerifyCallback",
+- "verify");
+-
+- builder.nonBlockingThreadPredicate(new Function<Predicate<Thread>, Predicate<Thread>>() {
+- @Override
+- public Predicate<Thread> apply(final Predicate<Thread> p) {
+- return new Predicate<Thread>() {
+- @Override
+- @SuppressJava6Requirement(reason = "Predicate#test")
+- public boolean test(Thread thread) {
+- return p.test(thread) || thread instanceof FastThreadLocalThread;
+- }
+- };
+- }
+- });
+- }
+-
+- @Override
+- public int compareTo(BlockHoundIntegration o) {
+- return 0;
+- }
+- }
+-}
+diff --git a/common/src/main/resources/META-INF/services/reactor.blockhound.integration.BlockHoundIntegration b/common/src/main/resources/META-INF/services/reactor.blockhound.integration.BlockHoundIntegration
+deleted file mode 100644
+index 5cf376dd8c..0000000000
+--- a/common/src/main/resources/META-INF/services/reactor.blockhound.integration.BlockHoundIntegration
++++ /dev/null
+@@ -1,14 +0,0 @@
+-# Copyright 2019 The Netty Project
+-#
+-# The Netty Project licenses this file to you under the Apache License,
+-# version 2.0 (the "License"); you may not use this file except in compliance
+-# with the License. You may obtain a copy of the License at:
+-#
+-# http://www.apache.org/licenses/LICENSE-2.0
+-#
+-# Unless required by applicable law or agreed to in writing, software
+-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+-# License for the specific language governing permissions and limitations
+-# under the License.
+-io.netty.util.internal.Hidden$NettyBlockHoundIntegration
+\ No newline at end of file
+diff --git a/pom.xml b/pom.xml
+index d00e3e88e0..d548aa5513 100644
+--- a/pom.xml
++++ b/pom.xml
+@@ -416,7 +416,6 @@
+ <module>testsuite-osgi</module>
+ <module>testsuite-shading</module>
+ <module>testsuite-native-image</module>
+- <module>transport-blockhound-tests</module>
+ <module>microbench</module>
+ <module>bom</module>
+ </modules>
+@@ -717,12 +716,6 @@
+ <scope>test</scope>
+ </dependency>
+
+- <!-- BlockHound integration -->
+- <dependency>
+- <groupId>io.projectreactor.tools</groupId>
+- <artifactId>blockhound</artifactId>
+- <version>1.0.3.RELEASE</version>
+- </dependency>
+ </dependencies>
+ </dependencyManagement>
+
+diff --git a/transport-blockhound-tests/pom.xml b/transport-blockhound-tests/pom.xml
+deleted file mode 100644
+index 359accd3c4..0000000000
+--- a/transport-blockhound-tests/pom.xml
++++ /dev/null
+@@ -1,92 +0,0 @@
+-<?xml version="1.0" encoding="UTF-8"?>
+-<!--
+- ~ Copyright 2019 The Netty Project
+- ~
+- ~ The Netty Project licenses this file to you under the Apache License,
+- ~ version 2.0 (the "License"); you may not use this file except in compliance
+- ~ with the License. You may obtain a copy of the License at:
+- ~
+- ~ http://www.apache.org/licenses/LICENSE-2.0
+- ~
+- ~ Unless required by applicable law or agreed to in writing, software
+- ~ distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- ~ WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- ~ License for the specific language governing permissions and limitations
+- ~ under the License.
+- -->
+-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+-
+- <modelVersion>4.0.0</modelVersion>
+- <parent>
+- <groupId>io.netty</groupId>
+- <artifactId>netty-parent</artifactId>
+- <version>4.1.51.Final</version>
+- </parent>
+-
+- <artifactId>netty-transport-blockhound-tests</artifactId>
+- <packaging>jar</packaging>
+- <description>
+- Tests for the BlockHound integration.
+- </description>
+-
+- <name>Netty/Transport/BlockHound/Tests</name>
+-
+- <profiles>
+- <profile>
+- <id>java13</id>
+- <activation>
+- <jdk>13</jdk>
+- </activation>
+- <properties>
+- <argLine.common>-XX:+AllowRedefinitionToAddDeleteMethods</argLine.common>
+- </properties>
+- </profile>
+- <profile>
+- <id>java14</id>
+- <activation>
+- <jdk>14</jdk>
+- </activation>
+- <properties>
+- <argLine.common>-XX:+AllowRedefinitionToAddDeleteMethods</argLine.common>
+- </properties>
+- </profile>
+- </profiles>
+-
+- <properties>
+- <maven.compiler.source>1.8</maven.compiler.source>
+- <maven.compiler.target>1.8</maven.compiler.target>
+- <!-- Needed for SelfSignedCertificate -->
+- <argLine.java9.extras>--add-exports java.base/sun.security.x509=ALL-UNNAMED</argLine.java9.extras>
+- <skipJapicmp>true</skipJapicmp>
+- </properties>
+-
+- <dependencies>
+- <dependency>
+- <groupId>${project.groupId}</groupId>
+- <artifactId>netty-transport</artifactId>
+- <version>${project.version}</version>
+- </dependency>
+- <dependency>
+- <groupId>${project.groupId}</groupId>
+- <artifactId>netty-handler</artifactId>
+- <version>${project.version}</version>
+- </dependency>
+- <dependency>
+- <groupId>${project.groupId}</groupId>
+- <artifactId>${tcnative.artifactId}</artifactId>
+- <classifier>${tcnative.classifier}</classifier>
+- <optional>true</optional>
+- </dependency>
+-
+- <dependency>
+- <groupId>org.bouncycastle</groupId>
+- <artifactId>bcpkix-jdk15on</artifactId>
+- <optional>true</optional>
+- </dependency>
+- <dependency>
+- <groupId>io.projectreactor.tools</groupId>
+- <artifactId>blockhound</artifactId>
+- <scope>test</scope>
+- </dependency>
+- </dependencies>
+-</project>
+diff --git a/transport-blockhound-tests/src/test/java/io/netty/util/internal/NettyBlockHoundIntegrationTest.java b/transport-blockhound-tests/src/test/java/io/netty/util/internal/NettyBlockHoundIntegrationTest.java
+deleted file mode 100644
+index 58e9284370..0000000000
+--- a/transport-blockhound-tests/src/test/java/io/netty/util/internal/NettyBlockHoundIntegrationTest.java
++++ /dev/null
+@@ -1,239 +0,0 @@
+-/*
+- * Copyright 2019 The Netty Project
+-
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+-
+- * http://www.apache.org/licenses/LICENSE-2.0
+-
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-package io.netty.util.internal;
+-
+-import io.netty.bootstrap.Bootstrap;
+-import io.netty.bootstrap.ServerBootstrap;
+-import io.netty.buffer.UnpooledByteBufAllocator;
+-import io.netty.channel.Channel;
+-import io.netty.channel.ChannelFuture;
+-import io.netty.channel.ChannelHandlerContext;
+-import io.netty.channel.ChannelInboundHandlerAdapter;
+-import io.netty.channel.ChannelInitializer;
+-import io.netty.channel.EventLoopGroup;
+-import io.netty.channel.nio.NioEventLoopGroup;
+-import io.netty.channel.socket.nio.NioServerSocketChannel;
+-import io.netty.channel.socket.nio.NioSocketChannel;
+-import io.netty.handler.ssl.SslContext;
+-import io.netty.handler.ssl.SslContextBuilder;
+-import io.netty.handler.ssl.SslHandler;
+-import io.netty.handler.ssl.SslHandshakeCompletionEvent;
+-import io.netty.handler.ssl.SslProvider;
+-import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
+-import io.netty.handler.ssl.util.SelfSignedCertificate;
+-import io.netty.util.ReferenceCountUtil;
+-import io.netty.util.concurrent.DefaultThreadFactory;
+-import io.netty.util.concurrent.EventExecutor;
+-import io.netty.util.concurrent.GlobalEventExecutor;
+-import io.netty.util.concurrent.ImmediateEventExecutor;
+-import io.netty.util.concurrent.ImmediateExecutor;
+-import io.netty.util.concurrent.ScheduledFuture;
+-import io.netty.util.concurrent.SingleThreadEventExecutor;
+-import io.netty.util.internal.Hidden.NettyBlockHoundIntegration;
+-import org.hamcrest.Matchers;
+-import org.junit.BeforeClass;
+-import org.junit.Test;
+-import reactor.blockhound.BlockHound;
+-import reactor.blockhound.BlockingOperationError;
+-import reactor.blockhound.integration.BlockHoundIntegration;
+-
+-import java.net.InetSocketAddress;
+-import java.util.ServiceLoader;
+-import java.util.concurrent.CountDownLatch;
+-import java.util.concurrent.ExecutionException;
+-import java.util.concurrent.Executor;
+-import java.util.concurrent.ExecutorService;
+-import java.util.concurrent.Executors;
+-import java.util.concurrent.FutureTask;
+-import java.util.concurrent.TimeUnit;
+-
+-import static org.junit.Assert.assertThat;
+-import static org.junit.Assert.assertTrue;
+-import static org.junit.Assert.fail;
+-
+-public class NettyBlockHoundIntegrationTest {
+-
+- @BeforeClass
+- public static void setUpClass() {
+- BlockHound.install();
+- }
+-
+- @Test
+- public void testServiceLoader() {
+- for (BlockHoundIntegration integration : ServiceLoader.load(BlockHoundIntegration.class)) {
+- if (integration instanceof NettyBlockHoundIntegration) {
+- return;
+- }
+- }
+-
+- fail("NettyBlockHoundIntegration cannot be loaded with ServiceLoader");
+- }
+-
+- @Test
+- public void testBlockingCallsInNettyThreads() throws Exception {
+- final FutureTask<Void> future = new FutureTask<>(() -> {
+- Thread.sleep(0);
+- return null;
+- });
+- GlobalEventExecutor.INSTANCE.execute(future);
+-
+- try {
+- future.get(5, TimeUnit.SECONDS);
+- fail("Expected an exception due to a blocking call but none was thrown");
+- } catch (ExecutionException e) {
+- assertThat(e.getCause(), Matchers.instanceOf(BlockingOperationError.class));
+- }
+- }
+-
+- @Test(timeout = 5000L)
+- public void testGlobalEventExecutorTakeTask() throws InterruptedException {
+- testEventExecutorTakeTask(GlobalEventExecutor.INSTANCE);
+- }
+-
+- @Test(timeout = 5000L)
+- public void testSingleThreadEventExecutorTakeTask() throws InterruptedException {
+- SingleThreadEventExecutor executor =
+- new SingleThreadEventExecutor(null, new DefaultThreadFactory("test"), true) {
+- @Override
+- protected void run() {
+- while (!confirmShutdown()) {
+- Runnable task = takeTask();
+- if (task != null) {
+- task.run();
+- }
+- }
+- }
+- };
+- testEventExecutorTakeTask(executor);
+- }
+-
+- private static void testEventExecutorTakeTask(EventExecutor eventExecutor) throws InterruptedException {
+- CountDownLatch latch = new CountDownLatch(1);
+- ScheduledFuture<?> f = eventExecutor.schedule(latch::countDown, 10, TimeUnit.MILLISECONDS);
+- f.sync();
+- latch.await();
+- }
+-
+- // Tests copied from io.netty.handler.ssl.SslHandlerTest
+- @Test
+- public void testHandshakeWithExecutorThatExecuteDirectory() throws Exception {
+- testHandshakeWithExecutor(Runnable::run);
+- }
+-
+- @Test
+- public void testHandshakeWithImmediateExecutor() throws Exception {
+- testHandshakeWithExecutor(ImmediateExecutor.INSTANCE);
+- }
+-
+- @Test
+- public void testHandshakeWithImmediateEventExecutor() throws Exception {
+- testHandshakeWithExecutor(ImmediateEventExecutor.INSTANCE);
+- }
+-
+- @Test
+- public void testHandshakeWithExecutor() throws Exception {
+- ExecutorService executorService = Executors.newCachedThreadPool();
+- try {
+- testHandshakeWithExecutor(executorService);
+- } finally {
+- executorService.shutdown();
+- }
+- }
+-
+- @Test
+- public void testTrustManagerVerify() throws Exception {
+- final SslContext sslClientCtx =
+- SslContextBuilder.forClient()
+- .trustManager(ResourcesUtil.getFile(getClass(), "mutual_auth_ca.pem"))
+- .build();
+-
+- final SslContext sslServerCtx =
+- SslContextBuilder.forServer(ResourcesUtil.getFile(getClass(), "localhost_server.pem"),
+- ResourcesUtil.getFile(getClass(), "localhost_server.key"),
+- null)
+- .build();
+-
+- final SslHandler clientSslHandler = sslClientCtx.newHandler(UnpooledByteBufAllocator.DEFAULT);
+- final SslHandler serverSslHandler = sslServerCtx.newHandler(UnpooledByteBufAllocator.DEFAULT);
+-
+- testHandshake(sslClientCtx, clientSslHandler, serverSslHandler);
+- }
+-
+- private static void testHandshakeWithExecutor(Executor executor) throws Exception {
+- String tlsVersion = "TLSv1.2";
+- final SslContext sslClientCtx = SslContextBuilder.forClient()
+- .trustManager(InsecureTrustManagerFactory.INSTANCE)
+- .sslProvider(SslProvider.JDK).protocols(tlsVersion).build();
+-
+- final SelfSignedCertificate cert = new SelfSignedCertificate();
+- final SslContext sslServerCtx = SslContextBuilder.forServer(cert.key(), cert.cert())
+- .sslProvider(SslProvider.JDK).protocols(tlsVersion).build();
+-
+- final SslHandler clientSslHandler = sslClientCtx.newHandler(UnpooledByteBufAllocator.DEFAULT, executor);
+- final SslHandler serverSslHandler = sslServerCtx.newHandler(UnpooledByteBufAllocator.DEFAULT, executor);
+-
+- testHandshake(sslClientCtx, clientSslHandler, serverSslHandler);
+- }
+-
+- private static void testHandshake(SslContext sslClientCtx, SslHandler clientSslHandler,
+- SslHandler serverSslHandler) throws Exception {
+- EventLoopGroup group = new NioEventLoopGroup();
+- Channel sc = null;
+- Channel cc = null;
+- try {
+- sc = new ServerBootstrap()
+- .group(group)
+- .channel(NioServerSocketChannel.class)
+- .childHandler(serverSslHandler)
+- .bind(new InetSocketAddress(0)).syncUninterruptibly().channel();
+-
+- ChannelFuture future = new Bootstrap()
+- .group(group)
+- .channel(NioSocketChannel.class)
+- .handler(new ChannelInitializer<Channel>() {
+- @Override
+- protected void initChannel(Channel ch) {
+- ch.pipeline()
+- .addLast(clientSslHandler)
+- .addLast(new ChannelInboundHandlerAdapter() {
+-
+- @Override
+- public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
+- if (evt instanceof SslHandshakeCompletionEvent &&
+- ((SslHandshakeCompletionEvent) evt).cause() != null) {
+- ((SslHandshakeCompletionEvent) evt).cause().printStackTrace();
+- }
+- ctx.fireUserEventTriggered(evt);
+- }
+- });
+- }
+- }).connect(sc.localAddress());
+- cc = future.syncUninterruptibly().channel();
+-
+- assertTrue(clientSslHandler.handshakeFuture().await().isSuccess());
+- assertTrue(serverSslHandler.handshakeFuture().await().isSuccess());
+- } finally {
+- if (cc != null) {
+- cc.close().syncUninterruptibly();
+- }
+- if (sc != null) {
+- sc.close().syncUninterruptibly();
+- }
+- group.shutdownGracefully();
+- ReferenceCountUtil.release(sslClientCtx);
+- }
+- }
+-}
+diff --git a/transport-blockhound-tests/src/test/resources/io/netty/util/internal/localhost_server.key b/transport-blockhound-tests/src/test/resources/io/netty/util/internal/localhost_server.key
+deleted file mode 100644
+index 9aa6611400..0000000000
+--- a/transport-blockhound-tests/src/test/resources/io/netty/util/internal/localhost_server.key
++++ /dev/null
+@@ -1,28 +0,0 @@
+------BEGIN PRIVATE KEY-----
+-MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDYrLtMlZzoe2BP
+-iCURF3So5XNLfsOLcAVERXXjnxqX6Mex55WdJiy6uWTFKbRHWJdbWELdZxVl5+GX
+-pMv3OdkKZt+19ZdSfByv6bB5RNdZOEGnKOHSY2XdnzYnF5JBaWEx0fvtvIPZOUlW
+-DWgsQzJk1UQhu+XnBc7P1hHYNvwsVNOR+HD9LGebDy+UcfiL34XwAyBdHUsbcIr8
+-hltABcj6vNbqOLndpU86DxU9z9b1PDmkFVfisElhpDEhpxmTCwI22Us1GC8D81LM
+-ZzMlbWSzTfNPEuqNzJYGiFt/XPwPkPPyVvti0XWPBQpwzJFFUX5xKsOGERolELRT
+-0yNQYznFAgMBAAECggEAOFR/xSNITbB1k3ejm1PrwlUUqlXkZIXU+LDOO0UL1t5v
+-vDKm1Not2sWECzYSZlID132UtJauG3YzUgdH95gUcv3XvyiAFLOriZhJht181vcn
+-KlwYiWfJ/dn8bCFWpqbM2/TpeB8AcCLSjAqkQI2ftlMziUmeNXdvEt1mej2hRay1
+-ULfoxlC0mftNRQptD5gBFzrc47O4mVpVEQt4yS3Qyzp2/9ds9UkhaCIFpXPVCalZ
+-ds7R+bDDP+wiYTkUcd8fvelaMkD3Wcy8DedGRShhILZvBYTDdWcpJ7+e5EkNlEq4
+-+Ys4Y/u6aFDJD53g3zCaJhatmdAZcct2MMmWH1vewQKBgQD3Y2S245cad1D9AqYD
+-ChZGp95EfRo3EzXk4VkE50bjZXjHq9fD8T0CWEZGWQZrXJCR+vBpEURy0mrPD8se
+-QQ0Q5+I27RadtfPnMd6ry9nDGMPxyd/10vzU6LazzLNE+uf9ljF1RHZu1iDAvInR
+-r1cQGbn/wKBF6BurPPIXABZEuQKBgQDgN6JHbIfDzHKhwEoUTvRrYJsTXqplD+h0
+-Whg+kSQyhtKdlpINFOoEj8FUNJvTjG8les1aoajyWIqikVdvHto/mrxrSIeRkEmt
+-X+KG+5ld2n466tzv1DmVcIGXSrBrH3lA0i6R8Ly26FLSqw0Z12fx5GUUa1qaVRqo
+-rwcrIZovbQKBgHa2mojs9AC+Sv3uvG1u9LuZKJ7jDaZqMI2R2d7xgOH0Op5Ohy6+
+-39D1PVvasqroc3Op4J36rEcRVDHi2Uy+WJ/JNpO2+AhcXRuPodP88ZWel8C6aB+V
+-zL/6oFntnAU5BgR5g2hLny2W0YbLsrMNmhDe15O0AvUo6cYla+K/pu/5AoGACr/g
+-EdiMMcDthf+4DX0zjqpVBPq25J18oYdoPierOpjoJBIB8oqcJZfWxvi2t8+1zHA0
+-xDGX7fZ8vwqEzJkIEaCTg/k4NqxaO+uq6pnJYoyFHMIB0aW1FQsNy3kTOC+MGqV5
+-Ahoukf5VajA1MpX3L8upZO84qsmFu6yYhWLZB4kCgYBlgSD5G4q6rX4ELa3XG61h
+-fDtu75IYEsjWm4vgJzHjeYT2xPIm9OFFYXjPghto0f1oH37ODD3DoXmsnmddgpmn
+-tH7aRWWHsSpB5zVgftV4urNCIsm87LWw8mvUGgCwYV1CtCX8warKokfeoA2ltz4u
+-oeuUzo98hN+aKRU5RO6Bmg==
+------END PRIVATE KEY-----
+diff --git a/transport-blockhound-tests/src/test/resources/io/netty/util/internal/localhost_server.pem b/transport-blockhound-tests/src/test/resources/io/netty/util/internal/localhost_server.pem
+deleted file mode 100644
+index 70759b29e5..0000000000
+--- a/transport-blockhound-tests/src/test/resources/io/netty/util/internal/localhost_server.pem
++++ /dev/null
+@@ -1,17 +0,0 @@
+------BEGIN CERTIFICATE-----
+-MIICozCCAYsCAnS/MA0GCSqGSIb3DQEBDQUAMBgxFjAUBgNVBAMTDU5ldHR5VGVz
+-dFJvb3QwIBcNMTcwMjE3MDMzMzQ0WhgPMjExNzAxMjQwMzMzNDRaMBQxEjAQBgNV
+-BAMTCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANis
+-u0yVnOh7YE+IJREXdKjlc0t+w4twBURFdeOfGpfox7HnlZ0mLLq5ZMUptEdYl1tY
+-Qt1nFWXn4Zeky/c52Qpm37X1l1J8HK/psHlE11k4Qaco4dJjZd2fNicXkkFpYTHR
+-++28g9k5SVYNaCxDMmTVRCG75ecFzs/WEdg2/CxU05H4cP0sZ5sPL5Rx+IvfhfAD
+-IF0dSxtwivyGW0AFyPq81uo4ud2lTzoPFT3P1vU8OaQVV+KwSWGkMSGnGZMLAjbZ
+-SzUYLwPzUsxnMyVtZLNN808S6o3MlgaIW39c/A+Q8/JW+2LRdY8FCnDMkUVRfnEq
+-w4YRGiUQtFPTI1BjOcUCAwEAATANBgkqhkiG9w0BAQ0FAAOCAQEAQNXnwE2MJFy5
+-ti07xyi8h/mY0Kl1dwZUqx4F9D9eoxLCq2/p3h/Z18AlOmjdW06pvC2sGtQtyEqL
+-YjuQFbMjXRo9c+6+d+xwdDKTu7+XOTHvznJ8xJpKnFOlohGq/n3efBIJSsaeasTU
+-slFzmdKYABDZzbsQ4X6YCIOF4XVdEQqmXpS+uEbn5C2sVtG+LXI8srmkVGpCcRew
+-SuTGanwxLparhBBeN1ARjKzNxXUWuK2UKZ9p8c7n7TXGhd12ZNTcLhk4rCnOFq1J
+-ySFvP5YL2q29fpEt+Tq0zm3V7An2qtaNDp26cEdevtKPjRyOLkCJx8OlZxc9DZvJ
+-HjalFDoRUw==
+------END CERTIFICATE-----
+diff --git a/transport-blockhound-tests/src/test/resources/io/netty/util/internal/mutual_auth_ca.pem b/transport-blockhound-tests/src/test/resources/io/netty/util/internal/mutual_auth_ca.pem
+deleted file mode 100644
+index 9c9241bc65..0000000000
+--- a/transport-blockhound-tests/src/test/resources/io/netty/util/internal/mutual_auth_ca.pem
++++ /dev/null
+@@ -1,19 +0,0 @@
+------BEGIN CERTIFICATE-----
+-MIIDLDCCAhSgAwIBAgIJAO1m5pioZhLLMA0GCSqGSIb3DQEBDQUAMBgxFjAUBgNV
+-BAMTDU5ldHR5VGVzdFJvb3QwHhcNMTcwMjE3MDMzMzQ0WhcNMTcwMzE5MDMzMzQ0
+-WjAYMRYwFAYDVQQDEw1OZXR0eVRlc3RSb290MIIBIjANBgkqhkiG9w0BAQEFAAOC
+-AQ8AMIIBCgKCAQEAnC7Y/p/TSWI1KxBKETfFKaRWCPEkoYn5G973WbCF0VDT90PX
+-xK6yHvhqNdDQZPmddgfDAQfjekHeeIFkjCKlvQu0js0G4Bubz4NffNumd/Mgsix8
+-SWJ13lPk+Ly4PDv0bK1zB6BxP1qQm1qxVwsPy9zNP8ylJrM0Div4TXHmnWOfc0JD
+-4/XPpfeUHH1tt/GMtsS2Gx6EpTVPD2w7LDKUza1/rQ7d9sqmFpgsNcI9Db/sAtFP
+-lK2iJku5WIXQkmHimn4bqZ9wkiXJ85pm5ggGQqGMPSbe+2Lh24AvZMIBiwPbkjEU
+-EDFXEJfKOC3Dl71JgWOthtHZ9vcCRDQ3Sky6AQIDAQABo3kwdzAdBgNVHQ4EFgQU
+-qT+cH8qrebiVPpKCBQDB6At2iOAwSAYDVR0jBEEwP4AUqT+cH8qrebiVPpKCBQDB
+-6At2iOChHKQaMBgxFjAUBgNVBAMTDU5ldHR5VGVzdFJvb3SCCQDtZuaYqGYSyzAM
+-BgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBDQUAA4IBAQCEemXTIew4pR2cHEFpVsW2
+-bLHXLAnC23wBMT46D3tqyxscukMYjFuWosCdEsgRW8d50BXy9o4dHWeg94+aDo3A
+-DX4OTRN/veQGIG7dgM6poDzFuVJlSN0ubKKg6gpDD60IhopZpMviFAOsmzr7OXwS
+-9hjbTqUWujMIEHQ95sPlQFdSaavYSFfqhSltWmVCPSbArxrw0lZ2QcnUqGN47EFp
+-whc5wFB+rSw/ojU1jBLMvgvgzf/8V8zr1IBTDSiHNlknGqGpOOaookzUh95YRiAT
+-hH82y9bBeflqroOeztqMpONpWoZjlz0sWbJNvXztXINL7LaNmVYOcoUrCcxPS54T
+------END CERTIFICATE-----
+--
+2.26.2
+
diff --git a/0002-Remove-NPN-ALPN.patch b/0002-Remove-NPN-ALPN.patch
deleted file mode 100644
index 73749cc..0000000
--- a/0002-Remove-NPN-ALPN.patch
+++ /dev/null
@@ -1,884 +0,0 @@
-From cfb6f2a620525a94d6964c287792f2645bff4f4a Mon Sep 17 00:00:00 2001
-From: Severin Gehwolf <sgehwolf(a)redhat.com>
-Date: Thu, 20 Oct 2016 16:18:10 +0200
-Subject: [PATCH 2/2] Remove NPN ALPN
-
----
- .../ssl/JdkAlpnApplicationProtocolNegotiator.java | 120 ---------
- .../io/netty/handler/ssl/JdkAlpnSslEngine.java | 124 ----------
- .../ssl/JdkNpnApplicationProtocolNegotiator.java | 120 ---------
- .../java/io/netty/handler/ssl/JdkNpnSslEngine.java | 122 ---------
- .../java/io/netty/handler/ssl/JdkSslContext.java | 44 ----
- .../io/netty/handler/ssl/JdkSslEngineTest.java | 273 ---------------------
- 6 files changed, 803 deletions(-)
- delete mode 100644 handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java
- delete mode 100644 handler/src/main/java/io/netty/handler/ssl/JdkAlpnSslEngine.java
- delete mode 100644 handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java
- delete mode 100644 handler/src/main/java/io/netty/handler/ssl/JdkNpnSslEngine.java
-
-diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java b/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java
-deleted file mode 100644
-index aaaf5b7..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java
-+++ /dev/null
-@@ -1,120 +0,0 @@
--/*
-- * Copyright 2014 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
--
--import javax.net.ssl.SSLEngine;
--
--/**
-- * The {@link JdkApplicationProtocolNegotiator} to use if you need ALPN and are using {@link SslProvider#JDK}.
-- */
--public final class JdkAlpnApplicationProtocolNegotiator extends JdkBaseApplicationProtocolNegotiator {
-- private static final SslEngineWrapperFactory ALPN_WRAPPER = new SslEngineWrapperFactory() {
-- {
-- if (!JdkAlpnSslEngine.isAvailable()) {
-- throw new RuntimeException("ALPN unsupported. Is your classpatch configured correctly?"
-- + " See http://www.eclipse.org/jetty/documentation/current/alpn-chapter.html#alpn...");
-- }
-- }
--
-- @Override
-- public SSLEngine wrapSslEngine(SSLEngine engine, JdkApplicationProtocolNegotiator applicationNegotiator,
-- boolean isServer) {
-- return new JdkAlpnSslEngine(engine, applicationNegotiator, isServer);
-- }
-- };
--
-- /**
-- * Create a new instance.
-- * @param protocols The order of iteration determines the preference of support for protocols.
-- */
-- public JdkAlpnApplicationProtocolNegotiator(Iterable<String> protocols) {
-- this(false, protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param protocols The order of iteration determines the preference of support for protocols.
-- */
-- public JdkAlpnApplicationProtocolNegotiator(String... protocols) {
-- this(false, protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param failIfNoCommonProtocols Fail with a fatal alert if not common protocols are detected.
-- * @param protocols The order of iteration determines the preference of support for protocols.
-- */
-- public JdkAlpnApplicationProtocolNegotiator(boolean failIfNoCommonProtocols, Iterable<String> protocols) {
-- this(failIfNoCommonProtocols, failIfNoCommonProtocols, protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param failIfNoCommonProtocols Fail with a fatal alert if not common protocols are detected.
-- * @param protocols The order of iteration determines the preference of support for protocols.
-- */
-- public JdkAlpnApplicationProtocolNegotiator(boolean failIfNoCommonProtocols, String... protocols) {
-- this(failIfNoCommonProtocols, failIfNoCommonProtocols, protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param clientFailIfNoCommonProtocols Client side fail with a fatal alert if not common protocols are detected.
-- * @param serverFailIfNoCommonProtocols Server side fail with a fatal alert if not common protocols are detected.
-- * @param protocols The order of iteration determines the preference of support for protocols.
-- */
-- public JdkAlpnApplicationProtocolNegotiator(boolean clientFailIfNoCommonProtocols,
-- boolean serverFailIfNoCommonProtocols, Iterable<String> protocols) {
-- this(serverFailIfNoCommonProtocols ? FAIL_SELECTOR_FACTORY : NO_FAIL_SELECTOR_FACTORY,
-- clientFailIfNoCommonProtocols ? FAIL_SELECTION_LISTENER_FACTORY : NO_FAIL_SELECTION_LISTENER_FACTORY,
-- protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param clientFailIfNoCommonProtocols Client side fail with a fatal alert if not common protocols are detected.
-- * @param serverFailIfNoCommonProtocols Server side fail with a fatal alert if not common protocols are detected.
-- * @param protocols The order of iteration determines the preference of support for protocols.
-- */
-- public JdkAlpnApplicationProtocolNegotiator(boolean clientFailIfNoCommonProtocols,
-- boolean serverFailIfNoCommonProtocols, String... protocols) {
-- this(serverFailIfNoCommonProtocols ? FAIL_SELECTOR_FACTORY : NO_FAIL_SELECTOR_FACTORY,
-- clientFailIfNoCommonProtocols ? FAIL_SELECTION_LISTENER_FACTORY : NO_FAIL_SELECTION_LISTENER_FACTORY,
-- protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param selectorFactory The factory which provides classes responsible for selecting the protocol.
-- * @param listenerFactory The factory which provides to be notified of which protocol was selected.
-- * @param protocols The order of iteration determines the preference of support for protocols.
-- */
-- public JdkAlpnApplicationProtocolNegotiator(ProtocolSelectorFactory selectorFactory,
-- ProtocolSelectionListenerFactory listenerFactory, Iterable<String> protocols) {
-- super(ALPN_WRAPPER, selectorFactory, listenerFactory, protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param selectorFactory The factory which provides classes responsible for selecting the protocol.
-- * @param listenerFactory The factory which provides to be notified of which protocol was selected.
-- * @param protocols The order of iteration determines the preference of support for protocols.
-- */
-- public JdkAlpnApplicationProtocolNegotiator(ProtocolSelectorFactory selectorFactory,
-- ProtocolSelectionListenerFactory listenerFactory, String... protocols) {
-- super(ALPN_WRAPPER, selectorFactory, listenerFactory, protocols);
-- }
--}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnSslEngine.java b/handler/src/main/java/io/netty/handler/ssl/JdkAlpnSslEngine.java
-deleted file mode 100644
-index bdf3aca..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnSslEngine.java
-+++ /dev/null
-@@ -1,124 +0,0 @@
--/*
-- * Copyright 2014 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
--
--import static io.netty.util.internal.ObjectUtil.checkNotNull;
--import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectionListener;
--import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector;
--
--import java.util.LinkedHashSet;
--import java.util.List;
--
--import javax.net.ssl.SSLEngine;
--import javax.net.ssl.SSLException;
--import javax.net.ssl.SSLHandshakeException;
--
--import org.eclipse.jetty.alpn.ALPN;
--import org.eclipse.jetty.alpn.ALPN.ClientProvider;
--import org.eclipse.jetty.alpn.ALPN.ServerProvider;
--
--final class JdkAlpnSslEngine extends JdkSslEngine {
-- private static boolean available;
--
-- static boolean isAvailable() {
-- updateAvailability();
-- return available;
-- }
--
-- private static void updateAvailability() {
-- if (available) {
-- return;
-- }
--
-- try {
-- // Always use bootstrap class loader.
-- Class.forName("sun.security.ssl.ALPNExtension", true, null);
-- available = true;
-- } catch (Exception ignore) {
-- // alpn-boot was not loaded.
-- }
-- }
--
-- JdkAlpnSslEngine(SSLEngine engine, final JdkApplicationProtocolNegotiator applicationNegotiator, boolean server) {
-- super(engine);
-- checkNotNull(applicationNegotiator, "applicationNegotiator");
--
-- if (server) {
-- final ProtocolSelector protocolSelector = checkNotNull(applicationNegotiator.protocolSelectorFactory()
-- .newSelector(this, new LinkedHashSet<String>(applicationNegotiator.protocols())),
-- "protocolSelector");
-- ALPN.put(engine, new ServerProvider() {
-- @Override
-- public String select(List<String> protocols) throws SSLException {
-- try {
-- return protocolSelector.select(protocols);
-- } catch (SSLHandshakeException e) {
-- throw e;
-- } catch (Throwable t) {
-- SSLHandshakeException e = new SSLHandshakeException(t.getMessage());
-- e.initCause(t);
-- throw e;
-- }
-- }
--
-- @Override
-- public void unsupported() {
-- protocolSelector.unsupported();
-- }
-- });
-- } else {
-- final ProtocolSelectionListener protocolListener = checkNotNull(applicationNegotiator
-- .protocolListenerFactory().newListener(this, applicationNegotiator.protocols()),
-- "protocolListener");
-- ALPN.put(engine, new ClientProvider() {
-- @Override
-- public List<String> protocols() {
-- return applicationNegotiator.protocols();
-- }
--
-- @Override
-- public void selected(String protocol) throws SSLException {
-- try {
-- protocolListener.selected(protocol);
-- } catch (SSLHandshakeException e) {
-- throw e;
-- } catch (Throwable t) {
-- SSLHandshakeException e = new SSLHandshakeException(t.getMessage());
-- e.initCause(t);
-- throw e;
-- }
-- }
--
-- @Override
-- public void unsupported() {
-- protocolListener.unsupported();
-- }
-- });
-- }
-- }
--
-- @Override
-- public void closeInbound() throws SSLException {
-- ALPN.remove(getWrappedEngine());
-- super.closeInbound();
-- }
--
-- @Override
-- public void closeOutbound() {
-- ALPN.remove(getWrappedEngine());
-- super.closeOutbound();
-- }
--}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java b/handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java
-deleted file mode 100644
-index c893f05..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java
-+++ /dev/null
-@@ -1,120 +0,0 @@
--/*
-- * Copyright 2014 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
--
--import javax.net.ssl.SSLEngine;
--
--/**
-- * The {@link JdkApplicationProtocolNegotiator} to use if you need NPN and are using {@link SslProvider#JDK}.
-- */
--public final class JdkNpnApplicationProtocolNegotiator extends JdkBaseApplicationProtocolNegotiator {
-- private static final SslEngineWrapperFactory NPN_WRAPPER = new SslEngineWrapperFactory() {
-- {
-- if (!JdkNpnSslEngine.isAvailable()) {
-- throw new RuntimeException("NPN unsupported. Is your classpatch configured correctly?"
-- + " See http://www.eclipse.org/jetty/documentation/current/npn-chapter.html#npn-s...");
-- }
-- }
--
-- @Override
-- public SSLEngine wrapSslEngine(SSLEngine engine, JdkApplicationProtocolNegotiator applicationNegotiator,
-- boolean isServer) {
-- return new JdkNpnSslEngine(engine, applicationNegotiator, isServer);
-- }
-- };
--
-- /**
-- * Create a new instance.
-- * @param protocols The order of iteration determines the preference of support for protocols.
-- */
-- public JdkNpnApplicationProtocolNegotiator(Iterable<String> protocols) {
-- this(false, protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param protocols The order of iteration determines the preference of support for protocols.
-- */
-- public JdkNpnApplicationProtocolNegotiator(String... protocols) {
-- this(false, protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param failIfNoCommonProtocols Fail with a fatal alert if not common protocols are detected.
-- * @param protocols The order of iteration determines the preference of support for protocols.
-- */
-- public JdkNpnApplicationProtocolNegotiator(boolean failIfNoCommonProtocols, Iterable<String> protocols) {
-- this(failIfNoCommonProtocols, failIfNoCommonProtocols, protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param failIfNoCommonProtocols Fail with a fatal alert if not common protocols are detected.
-- * @param protocols The order of iteration determines the preference of support for protocols.
-- */
-- public JdkNpnApplicationProtocolNegotiator(boolean failIfNoCommonProtocols, String... protocols) {
-- this(failIfNoCommonProtocols, failIfNoCommonProtocols, protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param clientFailIfNoCommonProtocols Client side fail with a fatal alert if not common protocols are detected.
-- * @param serverFailIfNoCommonProtocols Server side fail with a fatal alert if not common protocols are detected.
-- * @param protocols The order of iteration determines the preference of support for protocols.
-- */
-- public JdkNpnApplicationProtocolNegotiator(boolean clientFailIfNoCommonProtocols,
-- boolean serverFailIfNoCommonProtocols, Iterable<String> protocols) {
-- this(clientFailIfNoCommonProtocols ? FAIL_SELECTOR_FACTORY : NO_FAIL_SELECTOR_FACTORY,
-- serverFailIfNoCommonProtocols ? FAIL_SELECTION_LISTENER_FACTORY : NO_FAIL_SELECTION_LISTENER_FACTORY,
-- protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param clientFailIfNoCommonProtocols Client side fail with a fatal alert if not common protocols are detected.
-- * @param serverFailIfNoCommonProtocols Server side fail with a fatal alert if not common protocols are detected.
-- * @param protocols The order of iteration determines the preference of support for protocols.
-- */
-- public JdkNpnApplicationProtocolNegotiator(boolean clientFailIfNoCommonProtocols,
-- boolean serverFailIfNoCommonProtocols, String... protocols) {
-- this(clientFailIfNoCommonProtocols ? FAIL_SELECTOR_FACTORY : NO_FAIL_SELECTOR_FACTORY,
-- serverFailIfNoCommonProtocols ? FAIL_SELECTION_LISTENER_FACTORY : NO_FAIL_SELECTION_LISTENER_FACTORY,
-- protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param selectorFactory The factory which provides classes responsible for selecting the protocol.
-- * @param listenerFactory The factory which provides to be notified of which protocol was selected.
-- * @param protocols The order of iteration determines the preference of support for protocols.
-- */
-- public JdkNpnApplicationProtocolNegotiator(ProtocolSelectorFactory selectorFactory,
-- ProtocolSelectionListenerFactory listenerFactory, Iterable<String> protocols) {
-- super(NPN_WRAPPER, selectorFactory, listenerFactory, protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param selectorFactory The factory which provides classes responsible for selecting the protocol.
-- * @param listenerFactory The factory which provides to be notified of which protocol was selected.
-- * @param protocols The order of iteration determines the preference of support for protocols.
-- */
-- public JdkNpnApplicationProtocolNegotiator(ProtocolSelectorFactory selectorFactory,
-- ProtocolSelectionListenerFactory listenerFactory, String... protocols) {
-- super(NPN_WRAPPER, selectorFactory, listenerFactory, protocols);
-- }
--}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkNpnSslEngine.java b/handler/src/main/java/io/netty/handler/ssl/JdkNpnSslEngine.java
-deleted file mode 100644
-index 422727a..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/JdkNpnSslEngine.java
-+++ /dev/null
-@@ -1,122 +0,0 @@
--/*
-- * Copyright 2014 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--
--package io.netty.handler.ssl;
--
--import static io.netty.util.internal.ObjectUtil.checkNotNull;
--import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectionListener;
--import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector;
--import io.netty.util.internal.PlatformDependent;
--
--import java.util.LinkedHashSet;
--import java.util.List;
--
--import javax.net.ssl.SSLEngine;
--import javax.net.ssl.SSLException;
--
--import org.eclipse.jetty.npn.NextProtoNego;
--import org.eclipse.jetty.npn.NextProtoNego.ClientProvider;
--import org.eclipse.jetty.npn.NextProtoNego.ServerProvider;
--
--final class JdkNpnSslEngine extends JdkSslEngine {
-- private static boolean available;
--
-- static boolean isAvailable() {
-- updateAvailability();
-- return available;
-- }
--
-- private static void updateAvailability() {
-- if (available) {
-- return;
-- }
-- try {
-- // Always use bootstrap class loader.
-- Class.forName("sun.security.ssl.NextProtoNegoExtension", true, null);
-- available = true;
-- } catch (Exception ignore) {
-- // npn-boot was not loaded.
-- }
-- }
--
-- JdkNpnSslEngine(SSLEngine engine, final JdkApplicationProtocolNegotiator applicationNegotiator, boolean server) {
-- super(engine);
-- checkNotNull(applicationNegotiator, "applicationNegotiator");
--
-- if (server) {
-- final ProtocolSelectionListener protocolListener = checkNotNull(applicationNegotiator
-- .protocolListenerFactory().newListener(this, applicationNegotiator.protocols()),
-- "protocolListener");
-- NextProtoNego.put(engine, new ServerProvider() {
-- @Override
-- public void unsupported() {
-- protocolListener.unsupported();
-- }
--
-- @Override
-- public List<String> protocols() {
-- return applicationNegotiator.protocols();
-- }
--
-- @Override
-- public void protocolSelected(String protocol) {
-- try {
-- protocolListener.selected(protocol);
-- } catch (Throwable t) {
-- PlatformDependent.throwException(t);
-- }
-- }
-- });
-- } else {
-- final ProtocolSelector protocolSelector = checkNotNull(applicationNegotiator.protocolSelectorFactory()
-- .newSelector(this, new LinkedHashSet<String>(applicationNegotiator.protocols())),
-- "protocolSelector");
-- NextProtoNego.put(engine, new ClientProvider() {
-- @Override
-- public boolean supports() {
-- return true;
-- }
--
-- @Override
-- public void unsupported() {
-- protocolSelector.unsupported();
-- }
--
-- @Override
-- public String selectProtocol(List<String> protocols) {
-- try {
-- return protocolSelector.select(protocols);
-- } catch (Throwable t) {
-- PlatformDependent.throwException(t);
-- return null;
-- }
-- }
-- });
-- }
-- }
--
-- @Override
-- public void closeInbound() throws SSLException {
-- NextProtoNego.remove(getWrappedEngine());
-- super.closeInbound();
-- }
--
-- @Override
-- public void closeOutbound() {
-- NextProtoNego.remove(getWrappedEngine());
-- super.closeOutbound();
-- }
--}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkSslContext.java b/handler/src/main/java/io/netty/handler/ssl/JdkSslContext.java
-index 0a120eb..cdad232 100644
---- a/handler/src/main/java/io/netty/handler/ssl/JdkSslContext.java
-+++ b/handler/src/main/java/io/netty/handler/ssl/JdkSslContext.java
-@@ -270,50 +270,6 @@ public class JdkSslContext extends SslContext {
- switch(config.protocol()) {
- case NONE:
- return JdkDefaultApplicationProtocolNegotiator.INSTANCE;
-- case ALPN:
-- if (isServer) {
-- switch(config.selectorFailureBehavior()) {
-- case FATAL_ALERT:
-- return new JdkAlpnApplicationProtocolNegotiator(true, config.supportedProtocols());
-- case NO_ADVERTISE:
-- return new JdkAlpnApplicationProtocolNegotiator(false, config.supportedProtocols());
-- default:
-- throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ")
-- .append(config.selectorFailureBehavior()).append(" failure behavior").toString());
-- }
-- } else {
-- switch(config.selectedListenerFailureBehavior()) {
-- case ACCEPT:
-- return new JdkAlpnApplicationProtocolNegotiator(false, config.supportedProtocols());
-- case FATAL_ALERT:
-- return new JdkAlpnApplicationProtocolNegotiator(true, config.supportedProtocols());
-- default:
-- throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ")
-- .append(config.selectedListenerFailureBehavior()).append(" failure behavior").toString());
-- }
-- }
-- case NPN:
-- if (isServer) {
-- switch(config.selectedListenerFailureBehavior()) {
-- case ACCEPT:
-- return new JdkNpnApplicationProtocolNegotiator(false, config.supportedProtocols());
-- case FATAL_ALERT:
-- return new JdkNpnApplicationProtocolNegotiator(true, config.supportedProtocols());
-- default:
-- throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ")
-- .append(config.selectedListenerFailureBehavior()).append(" failure behavior").toString());
-- }
-- } else {
-- switch(config.selectorFailureBehavior()) {
-- case FATAL_ALERT:
-- return new JdkNpnApplicationProtocolNegotiator(true, config.supportedProtocols());
-- case NO_ADVERTISE:
-- return new JdkNpnApplicationProtocolNegotiator(false, config.supportedProtocols());
-- default:
-- throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ")
-- .append(config.selectorFailureBehavior()).append(" failure behavior").toString());
-- }
-- }
- default:
- throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ")
- .append(config.protocol()).append(" protocol").toString());
-diff --git a/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java b/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java
-index 9a57230..090f996 100644
---- a/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java
-+++ b/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java
-@@ -15,262 +15,15 @@
- */
- package io.netty.handler.ssl;
-
--import io.netty.handler.ssl.ApplicationProtocolConfig.Protocol;
--import io.netty.handler.ssl.ApplicationProtocolConfig.SelectedListenerFailureBehavior;
--import io.netty.handler.ssl.ApplicationProtocolConfig.SelectorFailureBehavior;
--import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector;
--import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectorFactory;
--import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
--import io.netty.handler.ssl.util.SelfSignedCertificate;
- import org.junit.Test;
-
--import javax.net.ssl.SSLEngine;
--import javax.net.ssl.SSLHandshakeException;
--import java.util.List;
--import java.util.Set;
--import java.util.concurrent.TimeUnit;
--
--import static org.junit.Assert.assertNull;
--import static org.junit.Assert.assertTrue;
--import static org.junit.Assume.assumeNoException;
--
- public class JdkSslEngineTest extends SSLEngineTest {
-- private static final String PREFERRED_APPLICATION_LEVEL_PROTOCOL = "my-protocol-http2";
-- private static final String FALLBACK_APPLICATION_LEVEL_PROTOCOL = "my-protocol-http1_1";
-- private static final String APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE = "my-protocol-FOO";
--
-- @Test
-- public void testNpn() throws Exception {
-- try {
-- // Typical code will not have to check this, but will get a initialization error on class load.
-- // Check in this test just in case we have multiple tests that just the class and we already ignored the
-- // initialization error.
-- if (!JdkNpnSslEngine.isAvailable()) {
-- throw tlsExtensionNotFound(Protocol.NPN);
-- }
-- ApplicationProtocolConfig apn = failingNegotiator(Protocol.NPN,
-- PREFERRED_APPLICATION_LEVEL_PROTOCOL);
-- setupHandlers(apn);
-- runTest();
-- } catch (SkipTestException e) {
-- // NPN availability is dependent on the java version. If NPN is not available because of
-- // java version incompatibility don't fail the test, but instead just skip the test
-- assumeNoException(e);
-- }
-- }
--
-- @Test
-- public void testNpnNoCompatibleProtocolsNoHandshakeFailure() throws Exception {
-- try {
-- // Typical code will not have to check this, but will get a initialization error on class load.
-- // Check in this test just in case we have multiple tests that just the class and we already ignored the
-- // initialization error.
-- if (!JdkNpnSslEngine.isAvailable()) {
-- throw tlsExtensionNotFound(Protocol.NPN);
-- }
-- ApplicationProtocolConfig clientApn = acceptingNegotiator(Protocol.NPN,
-- PREFERRED_APPLICATION_LEVEL_PROTOCOL);
-- ApplicationProtocolConfig serverApn = acceptingNegotiator(Protocol.NPN,
-- APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE);
-- setupHandlers(serverApn, clientApn);
-- runTest(null);
-- } catch (SkipTestException e) {
-- // ALPN availability is dependent on the java version. If ALPN is not available because of
-- // java version incompatibility don't fail the test, but instead just skip the test
-- assumeNoException(e);
-- }
-- }
--
-- @Test
-- public void testNpnNoCompatibleProtocolsClientHandshakeFailure() throws Exception {
-- try {
-- // Typical code will not have to check this, but will get a initialization error on class load.
-- // Check in this test just in case we have multiple tests that just the class and we already ignored the
-- // initialization error.
-- if (!JdkNpnSslEngine.isAvailable()) {
-- throw tlsExtensionNotFound(Protocol.NPN);
-- }
-- ApplicationProtocolConfig clientApn = failingNegotiator(Protocol.NPN,
-- PREFERRED_APPLICATION_LEVEL_PROTOCOL);
-- ApplicationProtocolConfig serverApn = acceptingNegotiator(Protocol.NPN,
-- APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE);
-- setupHandlers(serverApn, clientApn);
-- assertTrue(clientLatch.await(2, TimeUnit.SECONDS));
-- assertTrue(clientException instanceof SSLHandshakeException);
-- } catch (SkipTestException e) {
-- // NPN availability is dependent on the java version. If NPN is not available because of
-- // java version incompatibility don't fail the test, but instead just skip the test
-- assumeNoException(e);
-- }
-- }
--
-- @Test
-- public void testNpnNoCompatibleProtocolsServerHandshakeFailure() throws Exception {
-- try {
-- // Typical code will not have to check this, but will get a initialization error on class load.
-- // Check in this test just in case we have multiple tests that just the class and we already ignored the
-- // initialization error.
-- if (!JdkNpnSslEngine.isAvailable()) {
-- throw tlsExtensionNotFound(Protocol.NPN);
-- }
-- ApplicationProtocolConfig clientApn = acceptingNegotiator(Protocol.NPN,
-- PREFERRED_APPLICATION_LEVEL_PROTOCOL);
-- ApplicationProtocolConfig serverApn = failingNegotiator(Protocol.NPN,
-- APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE);
-- setupHandlers(serverApn, clientApn);
-- assertTrue(serverLatch.await(2, TimeUnit.SECONDS));
-- assertTrue(serverException instanceof SSLHandshakeException);
-- } catch (SkipTestException e) {
-- // NPN availability is dependent on the java version. If NPN is not available because of
-- // java version incompatibility don't fail the test, but instead just skip the test
-- assumeNoException(e);
-- }
-- }
--
-- @Test
-- public void testAlpn() throws Exception {
-- try {
-- // Typical code will not have to check this, but will get a initialization error on class load.
-- // Check in this test just in case we have multiple tests that just the class and we already ignored the
-- // initialization error.
-- if (!JdkAlpnSslEngine.isAvailable()) {
-- throw tlsExtensionNotFound(Protocol.ALPN);
-- }
-- ApplicationProtocolConfig apn = failingNegotiator(Protocol.ALPN,
-- PREFERRED_APPLICATION_LEVEL_PROTOCOL);
-- setupHandlers(apn);
-- runTest();
-- } catch (SkipTestException e) {
-- // ALPN availability is dependent on the java version. If ALPN is not available because of
-- // java version incompatibility don't fail the test, but instead just skip the test
-- assumeNoException(e);
-- }
-- }
--
-- @Test
-- public void testAlpnNoCompatibleProtocolsNoHandshakeFailure() throws Exception {
-- try {
-- // Typical code will not have to check this, but will get a initialization error on class load.
-- // Check in this test just in case we have multiple tests that just the class and we already ignored the
-- // initialization error.
-- if (!JdkAlpnSslEngine.isAvailable()) {
-- throw tlsExtensionNotFound(Protocol.ALPN);
-- }
-- ApplicationProtocolConfig clientApn = acceptingNegotiator(Protocol.ALPN,
-- PREFERRED_APPLICATION_LEVEL_PROTOCOL);
-- ApplicationProtocolConfig serverApn = acceptingNegotiator(Protocol.ALPN,
-- APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE);
-- setupHandlers(serverApn, clientApn);
-- runTest(null);
-- } catch (SkipTestException e) {
-- // ALPN availability is dependent on the java version. If ALPN is not available because of
-- // java version incompatibility don't fail the test, but instead just skip the test
-- assumeNoException(e);
-- }
-- }
--
-- @Test
-- public void testAlpnNoCompatibleProtocolsServerHandshakeFailure() throws Exception {
-- try {
-- // Typical code will not have to check this, but will get a initialization error on class load.
-- // Check in this test just in case we have multiple tests that just the class and we already ignored the
-- // initialization error.
-- if (!JdkAlpnSslEngine.isAvailable()) {
-- throw tlsExtensionNotFound(Protocol.ALPN);
-- }
-- ApplicationProtocolConfig clientApn = acceptingNegotiator(Protocol.ALPN,
-- PREFERRED_APPLICATION_LEVEL_PROTOCOL);
-- ApplicationProtocolConfig serverApn = failingNegotiator(Protocol.ALPN,
-- APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE);
-- setupHandlers(serverApn, clientApn);
-- assertTrue(serverLatch.await(2, TimeUnit.SECONDS));
-- assertTrue(serverException instanceof SSLHandshakeException);
-- } catch (SkipTestException e) {
-- // ALPN availability is dependent on the java version. If ALPN is not available because of
-- // java version incompatibility don't fail the test, but instead just skip the test
-- assumeNoException(e);
-- }
-- }
--
-- @Test
-- public void testAlpnCompatibleProtocolsDifferentClientOrder() throws Exception {
-- try {
-- // Typical code will not have to check this, but will get a initialization error on class load.
-- // Check in this test just in case we have multiple tests that just the class and we already ignored the
-- // initialization error.
-- if (!JdkAlpnSslEngine.isAvailable()) {
-- throw tlsExtensionNotFound(Protocol.ALPN);
-- }
-- // Even the preferred application protocol appears second in the client's list, it will be picked
-- // because it's the first one on server's list.
-- ApplicationProtocolConfig clientApn = acceptingNegotiator(Protocol.ALPN,
-- FALLBACK_APPLICATION_LEVEL_PROTOCOL, PREFERRED_APPLICATION_LEVEL_PROTOCOL);
-- ApplicationProtocolConfig serverApn = failingNegotiator(Protocol.ALPN,
-- PREFERRED_APPLICATION_LEVEL_PROTOCOL, FALLBACK_APPLICATION_LEVEL_PROTOCOL);
-- setupHandlers(serverApn, clientApn);
-- assertNull(serverException);
-- runTest(PREFERRED_APPLICATION_LEVEL_PROTOCOL);
-- } catch (SkipTestException e) {
-- // ALPN availability is dependent on the java version. If ALPN is not available because of
-- // java version incompatibility don't fail the test, but instead just skip the test
-- assumeNoException(e);
-- }
-- }
--
-- @Test
-- public void testAlpnNoCompatibleProtocolsClientHandshakeFailure() throws Exception {
-- try {
-- // Typical code will not have to check this, but will get a initialization error on class load.
-- // Check in this test just in case we have multiple tests that just the class and we already ignored the
-- // initialization error.
-- if (!JdkAlpnSslEngine.isAvailable()) {
-- throw tlsExtensionNotFound(Protocol.ALPN);
-- }
-- SelfSignedCertificate ssc = new SelfSignedCertificate();
-- JdkApplicationProtocolNegotiator clientApn = new JdkAlpnApplicationProtocolNegotiator(true, true,
-- PREFERRED_APPLICATION_LEVEL_PROTOCOL);
-- JdkApplicationProtocolNegotiator serverApn = new JdkAlpnApplicationProtocolNegotiator(
-- new ProtocolSelectorFactory() {
-- @Override
-- public ProtocolSelector newSelector(SSLEngine engine, Set<String> supportedProtocols) {
-- return new ProtocolSelector() {
-- @Override
-- public void unsupported() {
-- }
--
-- @Override
-- public String select(List<String> protocols) {
-- return APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE;
-- }
-- };
-- }
-- }, JdkBaseApplicationProtocolNegotiator.FAIL_SELECTION_LISTENER_FACTORY,
-- APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE);
--
-- SslContext serverSslCtx = new JdkSslServerContext(ssc.certificate(), ssc.privateKey(), null, null,
-- IdentityCipherSuiteFilter.INSTANCE, serverApn, 0, 0);
-- SslContext clientSslCtx = new JdkSslClientContext(null, InsecureTrustManagerFactory.INSTANCE, null,
-- IdentityCipherSuiteFilter.INSTANCE, clientApn, 0, 0);
--
-- setupHandlers(serverSslCtx, clientSslCtx);
-- assertTrue(clientLatch.await(2, TimeUnit.SECONDS));
-- assertTrue(clientException instanceof SSLHandshakeException);
-- } catch (SkipTestException e) {
-- // ALPN availability is dependent on the java version. If ALPN is not available because of
-- // java version incompatibility don't fail the test, but instead just skip the test
-- assumeNoException(e);
-- }
-- }
-
- @Test
- public void testEnablingAnAlreadyDisabledSslProtocol() throws Exception {
- testEnablingAnAlreadyDisabledSslProtocol(new String[]{}, new String[]{PROTOCOL_TLS_V1_2});
- }
-
-- private void runTest() throws Exception {
-- runTest(PREFERRED_APPLICATION_LEVEL_PROTOCOL);
-- }
--
- @Override
- protected SslProvider sslClientProvider() {
- return SslProvider.JDK;
-@@ -280,30 +33,4 @@ public class JdkSslEngineTest extends SSLEngineTest {
- protected SslProvider sslServerProvider() {
- return SslProvider.JDK;
- }
--
-- private ApplicationProtocolConfig failingNegotiator(Protocol protocol,
-- String... supportedProtocols) {
-- return new ApplicationProtocolConfig(protocol,
-- SelectorFailureBehavior.FATAL_ALERT,
-- SelectedListenerFailureBehavior.FATAL_ALERT,
-- supportedProtocols);
-- }
--
-- private ApplicationProtocolConfig acceptingNegotiator(Protocol protocol,
-- String... supportedProtocols) {
-- return new ApplicationProtocolConfig(protocol,
-- SelectorFailureBehavior.NO_ADVERTISE,
-- SelectedListenerFailureBehavior.ACCEPT,
-- supportedProtocols);
-- }
--
-- private SkipTestException tlsExtensionNotFound(Protocol protocol) {
-- throw new SkipTestException(protocol + " not on classpath");
-- }
--
-- private static final class SkipTestException extends RuntimeException {
-- public SkipTestException(String message) {
-- super(message);
-- }
-- }
- }
---
-2.7.4
-
diff --git a/0002-Remove-NPN.patch b/0002-Remove-NPN.patch
deleted file mode 100644
index 77a340a..0000000
--- a/0002-Remove-NPN.patch
+++ /dev/null
@@ -1,353 +0,0 @@
-From f7b8e27b5f55c4a21cf84fb56a616b8bfd4af8da Mon Sep 17 00:00:00 2001
-From: Michael Simacek <msimacek(a)redhat.com>
-Date: Fri, 7 Jul 2017 16:07:23 +0200
-Subject: [PATCH 2/3] Remove NPN
-
----
- handler/pom.xml | 5 -
- .../ssl/JdkNpnApplicationProtocolNegotiator.java | 120 --------------------
- .../java/io/netty/handler/ssl/JdkSslContext.java | 30 -----
- .../io/netty/handler/ssl/JettyNpnSslEngine.java | 122 ---------------------
- .../io/netty/handler/ssl/JdkSslEngineTest.java | 2 +-
- 5 files changed, 1 insertion(+), 278 deletions(-)
- delete mode 100644 handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java
- delete mode 100644 handler/src/main/java/io/netty/handler/ssl/JettyNpnSslEngine.java
-
-diff --git a/handler/pom.xml b/handler/pom.xml
-index d0ed1bc..52e63ca 100644
---- a/handler/pom.xml
-+++ b/handler/pom.xml
-@@ -55,11 +55,6 @@
- <optional>true</optional>
- </dependency>
- <dependency>
-- <groupId>org.eclipse.jetty.npn</groupId>
-- <artifactId>npn-api</artifactId>
-- <optional>true</optional>
-- </dependency>
-- <dependency>
- <groupId>org.eclipse.jetty.alpn</groupId>
- <artifactId>alpn-api</artifactId>
- <optional>true</optional>
-diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java b/handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java
-deleted file mode 100644
-index 06b29b7..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java
-+++ /dev/null
-@@ -1,120 +0,0 @@
--/*
-- * Copyright 2014 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
--
--import javax.net.ssl.SSLEngine;
--
--/**
-- * The {@link JdkApplicationProtocolNegotiator} to use if you need NPN and are using {@link SslProvider#JDK}.
-- */
--public final class JdkNpnApplicationProtocolNegotiator extends JdkBaseApplicationProtocolNegotiator {
-- private static final SslEngineWrapperFactory NPN_WRAPPER = new SslEngineWrapperFactory() {
-- {
-- if (!JettyNpnSslEngine.isAvailable()) {
-- throw new RuntimeException("NPN unsupported. Is your classpath configured correctly?"
-- + " See https://wiki.eclipse.org/Jetty/Feature/NPN");
-- }
-- }
--
-- @Override
-- public SSLEngine wrapSslEngine(SSLEngine engine, JdkApplicationProtocolNegotiator applicationNegotiator,
-- boolean isServer) {
-- return new JettyNpnSslEngine(engine, applicationNegotiator, isServer);
-- }
-- };
--
-- /**
-- * Create a new instance.
-- * @param protocols The order of iteration determines the preference of support for protocols.
-- */
-- public JdkNpnApplicationProtocolNegotiator(Iterable<String> protocols) {
-- this(false, protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param protocols The order of iteration determines the preference of support for protocols.
-- */
-- public JdkNpnApplicationProtocolNegotiator(String... protocols) {
-- this(false, protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param failIfNoCommonProtocols Fail with a fatal alert if not common protocols are detected.
-- * @param protocols The order of iteration determines the preference of support for protocols.
-- */
-- public JdkNpnApplicationProtocolNegotiator(boolean failIfNoCommonProtocols, Iterable<String> protocols) {
-- this(failIfNoCommonProtocols, failIfNoCommonProtocols, protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param failIfNoCommonProtocols Fail with a fatal alert if not common protocols are detected.
-- * @param protocols The order of iteration determines the preference of support for protocols.
-- */
-- public JdkNpnApplicationProtocolNegotiator(boolean failIfNoCommonProtocols, String... protocols) {
-- this(failIfNoCommonProtocols, failIfNoCommonProtocols, protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param clientFailIfNoCommonProtocols Client side fail with a fatal alert if not common protocols are detected.
-- * @param serverFailIfNoCommonProtocols Server side fail with a fatal alert if not common protocols are detected.
-- * @param protocols The order of iteration determines the preference of support for protocols.
-- */
-- public JdkNpnApplicationProtocolNegotiator(boolean clientFailIfNoCommonProtocols,
-- boolean serverFailIfNoCommonProtocols, Iterable<String> protocols) {
-- this(clientFailIfNoCommonProtocols ? FAIL_SELECTOR_FACTORY : NO_FAIL_SELECTOR_FACTORY,
-- serverFailIfNoCommonProtocols ? FAIL_SELECTION_LISTENER_FACTORY : NO_FAIL_SELECTION_LISTENER_FACTORY,
-- protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param clientFailIfNoCommonProtocols Client side fail with a fatal alert if not common protocols are detected.
-- * @param serverFailIfNoCommonProtocols Server side fail with a fatal alert if not common protocols are detected.
-- * @param protocols The order of iteration determines the preference of support for protocols.
-- */
-- public JdkNpnApplicationProtocolNegotiator(boolean clientFailIfNoCommonProtocols,
-- boolean serverFailIfNoCommonProtocols, String... protocols) {
-- this(clientFailIfNoCommonProtocols ? FAIL_SELECTOR_FACTORY : NO_FAIL_SELECTOR_FACTORY,
-- serverFailIfNoCommonProtocols ? FAIL_SELECTION_LISTENER_FACTORY : NO_FAIL_SELECTION_LISTENER_FACTORY,
-- protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param selectorFactory The factory which provides classes responsible for selecting the protocol.
-- * @param listenerFactory The factory which provides to be notified of which protocol was selected.
-- * @param protocols The order of iteration determines the preference of support for protocols.
-- */
-- public JdkNpnApplicationProtocolNegotiator(ProtocolSelectorFactory selectorFactory,
-- ProtocolSelectionListenerFactory listenerFactory, Iterable<String> protocols) {
-- super(NPN_WRAPPER, selectorFactory, listenerFactory, protocols);
-- }
--
-- /**
-- * Create a new instance.
-- * @param selectorFactory The factory which provides classes responsible for selecting the protocol.
-- * @param listenerFactory The factory which provides to be notified of which protocol was selected.
-- * @param protocols The order of iteration determines the preference of support for protocols.
-- */
-- public JdkNpnApplicationProtocolNegotiator(ProtocolSelectorFactory selectorFactory,
-- ProtocolSelectionListenerFactory listenerFactory, String... protocols) {
-- super(NPN_WRAPPER, selectorFactory, listenerFactory, protocols);
-- }
--}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkSslContext.java b/handler/src/main/java/io/netty/handler/ssl/JdkSslContext.java
-index 0ad6639..d5b86ff 100644
---- a/handler/src/main/java/io/netty/handler/ssl/JdkSslContext.java
-+++ b/handler/src/main/java/io/netty/handler/ssl/JdkSslContext.java
-@@ -288,47 +288,17 @@ public class JdkSslContext extends SslContext {
- case ALPN:
- if (isServer) {
- switch(config.selectorFailureBehavior()) {
-- case FATAL_ALERT:
-- return new JdkAlpnApplicationProtocolNegotiator(true, config.supportedProtocols());
-- case NO_ADVERTISE:
-- return new JdkAlpnApplicationProtocolNegotiator(false, config.supportedProtocols());
- default:
- throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ")
- .append(config.selectorFailureBehavior()).append(" failure behavior").toString());
- }
- } else {
- switch(config.selectedListenerFailureBehavior()) {
-- case ACCEPT:
-- return new JdkAlpnApplicationProtocolNegotiator(false, config.supportedProtocols());
-- case FATAL_ALERT:
-- return new JdkAlpnApplicationProtocolNegotiator(true, config.supportedProtocols());
- default:
- throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ")
- .append(config.selectedListenerFailureBehavior()).append(" failure behavior").toString());
- }
- }
-- case NPN:
-- if (isServer) {
-- switch(config.selectedListenerFailureBehavior()) {
-- case ACCEPT:
-- return new JdkNpnApplicationProtocolNegotiator(false, config.supportedProtocols());
-- case FATAL_ALERT:
-- return new JdkNpnApplicationProtocolNegotiator(true, config.supportedProtocols());
-- default:
-- throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ")
-- .append(config.selectedListenerFailureBehavior()).append(" failure behavior").toString());
-- }
-- } else {
-- switch(config.selectorFailureBehavior()) {
-- case FATAL_ALERT:
-- return new JdkNpnApplicationProtocolNegotiator(true, config.supportedProtocols());
-- case NO_ADVERTISE:
-- return new JdkNpnApplicationProtocolNegotiator(false, config.supportedProtocols());
-- default:
-- throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ")
-- .append(config.selectorFailureBehavior()).append(" failure behavior").toString());
-- }
-- }
- default:
- throw new UnsupportedOperationException(new StringBuilder("JDK provider does not support ")
- .append(config.protocol()).append(" protocol").toString());
-diff --git a/handler/src/main/java/io/netty/handler/ssl/JettyNpnSslEngine.java b/handler/src/main/java/io/netty/handler/ssl/JettyNpnSslEngine.java
-deleted file mode 100644
-index 77e7366..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/JettyNpnSslEngine.java
-+++ /dev/null
-@@ -1,122 +0,0 @@
--/*
-- * Copyright 2014 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--
--package io.netty.handler.ssl;
--
--import static io.netty.util.internal.ObjectUtil.checkNotNull;
--import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectionListener;
--import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector;
--import io.netty.util.internal.PlatformDependent;
--
--import java.util.LinkedHashSet;
--import java.util.List;
--
--import javax.net.ssl.SSLEngine;
--import javax.net.ssl.SSLException;
--
--import org.eclipse.jetty.npn.NextProtoNego;
--import org.eclipse.jetty.npn.NextProtoNego.ClientProvider;
--import org.eclipse.jetty.npn.NextProtoNego.ServerProvider;
--
--final class JettyNpnSslEngine extends JdkSslEngine {
-- private static boolean available;
--
-- static boolean isAvailable() {
-- updateAvailability();
-- return available;
-- }
--
-- private static void updateAvailability() {
-- if (available) {
-- return;
-- }
-- try {
-- // Always use bootstrap class loader.
-- Class.forName("sun.security.ssl.NextProtoNegoExtension", true, null);
-- available = true;
-- } catch (Exception ignore) {
-- // npn-boot was not loaded.
-- }
-- }
--
-- JettyNpnSslEngine(SSLEngine engine, final JdkApplicationProtocolNegotiator applicationNegotiator, boolean server) {
-- super(engine);
-- checkNotNull(applicationNegotiator, "applicationNegotiator");
--
-- if (server) {
-- final ProtocolSelectionListener protocolListener = checkNotNull(applicationNegotiator
-- .protocolListenerFactory().newListener(this, applicationNegotiator.protocols()),
-- "protocolListener");
-- NextProtoNego.put(engine, new ServerProvider() {
-- @Override
-- public void unsupported() {
-- protocolListener.unsupported();
-- }
--
-- @Override
-- public List<String> protocols() {
-- return applicationNegotiator.protocols();
-- }
--
-- @Override
-- public void protocolSelected(String protocol) {
-- try {
-- protocolListener.selected(protocol);
-- } catch (Throwable t) {
-- PlatformDependent.throwException(t);
-- }
-- }
-- });
-- } else {
-- final ProtocolSelector protocolSelector = checkNotNull(applicationNegotiator.protocolSelectorFactory()
-- .newSelector(this, new LinkedHashSet<String>(applicationNegotiator.protocols())),
-- "protocolSelector");
-- NextProtoNego.put(engine, new ClientProvider() {
-- @Override
-- public boolean supports() {
-- return true;
-- }
--
-- @Override
-- public void unsupported() {
-- protocolSelector.unsupported();
-- }
--
-- @Override
-- public String selectProtocol(List<String> protocols) {
-- try {
-- return protocolSelector.select(protocols);
-- } catch (Throwable t) {
-- PlatformDependent.throwException(t);
-- return null;
-- }
-- }
-- });
-- }
-- }
--
-- @Override
-- public void closeInbound() throws SSLException {
-- NextProtoNego.remove(getWrappedEngine());
-- super.closeInbound();
-- }
--
-- @Override
-- public void closeOutbound() {
-- NextProtoNego.remove(getWrappedEngine());
-- super.closeOutbound();
-- }
--}
-diff --git a/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java b/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java
-index d6cd94d..4489b16 100644
---- a/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java
-+++ b/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java
-@@ -46,7 +46,7 @@ public class JdkSslEngineTest extends SSLEngineTest {
- NPN_DEFAULT {
- @Override
- boolean isAvailable() {
-- return JettyNpnSslEngine.isAvailable();
-+ return false;
- }
-
- @Override
---
-2.9.4
-
diff --git a/0002-Remove-optional-dep-conscrypt.patch b/0002-Remove-optional-dep-conscrypt.patch
new file mode 100644
index 0000000..0a9cfef
--- /dev/null
+++ b/0002-Remove-optional-dep-conscrypt.patch
@@ -0,0 +1,444 @@
+From 1a72454998ec91895648443c176ec41e542903e8 Mon Sep 17 00:00:00 2001
+From: Mat Booth <mat.booth(a)redhat.com>
+Date: Mon, 7 Sep 2020 13:24:30 +0100
+Subject: [PATCH 2/5] Remove optional dep conscrypt
+
+---
+ handler/pom.xml | 6 -
+ .../java/io/netty/handler/ssl/Conscrypt.java | 81 --------
+ .../handler/ssl/ConscryptAlpnSslEngine.java | 196 ------------------
+ .../JdkAlpnApplicationProtocolNegotiator.java | 8 +-
+ .../java/io/netty/handler/ssl/SslHandler.java | 47 +----
+ pom.xml | 10 -
+ 6 files changed, 2 insertions(+), 346 deletions(-)
+ delete mode 100644 handler/src/main/java/io/netty/handler/ssl/Conscrypt.java
+ delete mode 100644 handler/src/main/java/io/netty/handler/ssl/ConscryptAlpnSslEngine.java
+
+diff --git a/handler/pom.xml b/handler/pom.xml
+index c8e26119bd..378aeda2fe 100644
+--- a/handler/pom.xml
++++ b/handler/pom.xml
+@@ -81,12 +81,6 @@
+ <artifactId>alpn-api</artifactId>
+ <optional>true</optional>
+ </dependency>
+- <dependency>
+- <groupId>${conscrypt.groupId}</groupId>
+- <artifactId>${conscrypt.artifactId}</artifactId>
+- <classifier>${conscrypt.classifier}</classifier>
+- <optional>true</optional>
+- </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-core</artifactId>
+diff --git a/handler/src/main/java/io/netty/handler/ssl/Conscrypt.java b/handler/src/main/java/io/netty/handler/ssl/Conscrypt.java
+deleted file mode 100644
+index d2f015f90f..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/Conscrypt.java
++++ /dev/null
+@@ -1,81 +0,0 @@
+-/*
+- * Copyright 2017 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- * http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-package io.netty.handler.ssl;
+-
+-import io.netty.util.internal.PlatformDependent;
+-
+-import javax.net.ssl.SSLEngine;
+-import java.lang.reflect.InvocationTargetException;
+-import java.lang.reflect.Method;
+-
+-/**
+- * Contains methods that can be used to detect if conscrypt is usable.
+- */
+-final class Conscrypt {
+- // This class exists to avoid loading other conscrypt related classes using features only available in JDK8+,
+- // because we need to maintain JDK6+ runtime compatibility.
+- private static final Method IS_CONSCRYPT_SSLENGINE = loadIsConscryptEngine();
+- private static final boolean CAN_INSTANCE_PROVIDER = canInstanceProvider();
+-
+- private static Method loadIsConscryptEngine() {
+- try {
+- Class<?> conscryptClass = Class.forName("org.conscrypt.Conscrypt", true,
+- ConscryptAlpnSslEngine.class.getClassLoader());
+- return conscryptClass.getMethod("isConscrypt", SSLEngine.class);
+- } catch (Throwable ignore) {
+- // Conscrypt was not loaded.
+- return null;
+- }
+- }
+-
+- private static boolean canInstanceProvider() {
+- try {
+- Class<?> providerClass = Class.forName("org.conscrypt.OpenSSLProvider", true,
+- ConscryptAlpnSslEngine.class.getClassLoader());
+- providerClass.newInstance();
+- return true;
+- } catch (Throwable ignore) {
+- return false;
+- }
+- }
+-
+- /**
+- * Indicates whether or not conscrypt is available on the current system.
+- */
+- static boolean isAvailable() {
+- return CAN_INSTANCE_PROVIDER && IS_CONSCRYPT_SSLENGINE != null &&
+- ((PlatformDependent.javaVersion() >= 8 &&
+- // Only works on Java14 and earlier for now
+- // See https://github.com/google/conscrypt/issues/838
+- PlatformDependent.javaVersion() < 15) || PlatformDependent.isAndroid());
+- }
+-
+- static boolean isEngineSupported(SSLEngine engine) {
+- return isAvailable() && isConscryptEngine(engine);
+- }
+-
+- private static boolean isConscryptEngine(SSLEngine engine) {
+- try {
+- return (Boolean) IS_CONSCRYPT_SSLENGINE.invoke(null, engine);
+- } catch (IllegalAccessException ignore) {
+- return false;
+- } catch (InvocationTargetException ex) {
+- throw new RuntimeException(ex);
+- }
+- }
+-
+- private Conscrypt() { }
+-}
+diff --git a/handler/src/main/java/io/netty/handler/ssl/ConscryptAlpnSslEngine.java b/handler/src/main/java/io/netty/handler/ssl/ConscryptAlpnSslEngine.java
+deleted file mode 100644
+index d9767a7106..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/ConscryptAlpnSslEngine.java
++++ /dev/null
+@@ -1,196 +0,0 @@
+-/*
+- * Copyright 2017 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- * http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-package io.netty.handler.ssl;
+-
+-import static io.netty.handler.ssl.SslUtils.toSSLHandshakeException;
+-import static io.netty.util.internal.ObjectUtil.checkNotNull;
+-import static java.lang.Math.min;
+-
+-import io.netty.buffer.ByteBuf;
+-import io.netty.buffer.ByteBufAllocator;
+-import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectionListener;
+-import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector;
+-import java.nio.ByteBuffer;
+-import java.util.Collections;
+-import java.util.LinkedHashSet;
+-import java.util.List;
+-import javax.net.ssl.SSLEngine;
+-import javax.net.ssl.SSLEngineResult;
+-import javax.net.ssl.SSLException;
+-
+-import io.netty.util.internal.SystemPropertyUtil;
+-import org.conscrypt.AllocatedBuffer;
+-import org.conscrypt.BufferAllocator;
+-import org.conscrypt.Conscrypt;
+-import org.conscrypt.HandshakeListener;
+-
+-/**
+- * A {@link JdkSslEngine} that uses the Conscrypt provider or SSL with ALPN.
+- */
+-abstract class ConscryptAlpnSslEngine extends JdkSslEngine {
+- private static final boolean USE_BUFFER_ALLOCATOR = SystemPropertyUtil.getBoolean(
+- "io.netty.handler.ssl.conscrypt.useBufferAllocator", true);
+-
+- static ConscryptAlpnSslEngine newClientEngine(SSLEngine engine, ByteBufAllocator alloc,
+- JdkApplicationProtocolNegotiator applicationNegotiator) {
+- return new ClientEngine(engine, alloc, applicationNegotiator);
+- }
+-
+- static ConscryptAlpnSslEngine newServerEngine(SSLEngine engine, ByteBufAllocator alloc,
+- JdkApplicationProtocolNegotiator applicationNegotiator) {
+- return new ServerEngine(engine, alloc, applicationNegotiator);
+- }
+-
+- private ConscryptAlpnSslEngine(SSLEngine engine, ByteBufAllocator alloc, List<String> protocols) {
+- super(engine);
+-
+- // Configure the Conscrypt engine to use Netty's buffer allocator. This is a trade-off of memory vs
+- // performance.
+- //
+- // If no allocator is provided, the engine will internally allocate a direct buffer of max packet size in
+- // order to optimize JNI calls (this happens the first time it is provided a non-direct buffer from the
+- // application).
+- //
+- // Alternatively, if an allocator is provided, no internal buffer will be created and direct buffers will be
+- // retrieved from the allocator on-demand.
+- if (USE_BUFFER_ALLOCATOR) {
+- Conscrypt.setBufferAllocator(engine, new BufferAllocatorAdapter(alloc));
+- }
+-
+- // Set the list of supported ALPN protocols on the engine.
+- Conscrypt.setApplicationProtocols(engine, protocols.toArray(new String[0]));
+- }
+-
+- /**
+- * Calculates the maximum size of the encrypted output buffer required to wrap the given plaintext bytes. Assumes
+- * as a worst case that there is one TLS record per buffer.
+- *
+- * @param plaintextBytes the number of plaintext bytes to be wrapped.
+- * @param numBuffers the number of buffers that the plaintext bytes are spread across.
+- * @return the maximum size of the encrypted output buffer required for the wrap operation.
+- */
+- final int calculateOutNetBufSize(int plaintextBytes, int numBuffers) {
+- // Assuming a max of one frame per component in a composite buffer.
+- long maxOverhead = (long) Conscrypt.maxSealOverhead(getWrappedEngine()) * numBuffers;
+- // TODO(nmittler): update this to use MAX_ENCRYPTED_PACKET_LENGTH instead of Integer.MAX_VALUE
+- return (int) min(Integer.MAX_VALUE, plaintextBytes + maxOverhead);
+- }
+-
+- final SSLEngineResult unwrap(ByteBuffer[] srcs, ByteBuffer[] dests) throws SSLException {
+- return Conscrypt.unwrap(getWrappedEngine(), srcs, dests);
+- }
+-
+- private static final class ClientEngine extends ConscryptAlpnSslEngine {
+- private final ProtocolSelectionListener protocolListener;
+-
+- ClientEngine(SSLEngine engine, ByteBufAllocator alloc,
+- JdkApplicationProtocolNegotiator applicationNegotiator) {
+- super(engine, alloc, applicationNegotiator.protocols());
+- // Register for completion of the handshake.
+- Conscrypt.setHandshakeListener(engine, new HandshakeListener() {
+- @Override
+- public void onHandshakeFinished() throws SSLException {
+- selectProtocol();
+- }
+- });
+-
+- protocolListener = checkNotNull(applicationNegotiator
+- .protocolListenerFactory().newListener(this, applicationNegotiator.protocols()),
+- "protocolListener");
+- }
+-
+- private void selectProtocol() throws SSLException {
+- String protocol = Conscrypt.getApplicationProtocol(getWrappedEngine());
+- try {
+- protocolListener.selected(protocol);
+- } catch (Throwable e) {
+- throw toSSLHandshakeException(e);
+- }
+- }
+- }
+-
+- private static final class ServerEngine extends ConscryptAlpnSslEngine {
+- private final ProtocolSelector protocolSelector;
+-
+- ServerEngine(SSLEngine engine, ByteBufAllocator alloc,
+- JdkApplicationProtocolNegotiator applicationNegotiator) {
+- super(engine, alloc, applicationNegotiator.protocols());
+-
+- // Register for completion of the handshake.
+- Conscrypt.setHandshakeListener(engine, new HandshakeListener() {
+- @Override
+- public void onHandshakeFinished() throws SSLException {
+- selectProtocol();
+- }
+- });
+-
+- protocolSelector = checkNotNull(applicationNegotiator.protocolSelectorFactory()
+- .newSelector(this,
+- new LinkedHashSet<String>(applicationNegotiator.protocols())),
+- "protocolSelector");
+- }
+-
+- private void selectProtocol() throws SSLException {
+- try {
+- String protocol = Conscrypt.getApplicationProtocol(getWrappedEngine());
+- protocolSelector.select(protocol != null ? Collections.singletonList(protocol)
+- : Collections.<String>emptyList());
+- } catch (Throwable e) {
+- throw toSSLHandshakeException(e);
+- }
+- }
+- }
+-
+- private static final class BufferAllocatorAdapter extends BufferAllocator {
+- private final ByteBufAllocator alloc;
+-
+- BufferAllocatorAdapter(ByteBufAllocator alloc) {
+- this.alloc = alloc;
+- }
+-
+- @Override
+- public AllocatedBuffer allocateDirectBuffer(int capacity) {
+- return new BufferAdapter(alloc.directBuffer(capacity));
+- }
+- }
+-
+- private static final class BufferAdapter extends AllocatedBuffer {
+- private final ByteBuf nettyBuffer;
+- private final ByteBuffer buffer;
+-
+- BufferAdapter(ByteBuf nettyBuffer) {
+- this.nettyBuffer = nettyBuffer;
+- buffer = nettyBuffer.nioBuffer(0, nettyBuffer.capacity());
+- }
+-
+- @Override
+- public ByteBuffer nioBuffer() {
+- return buffer;
+- }
+-
+- @Override
+- public AllocatedBuffer retain() {
+- nettyBuffer.retain();
+- return this;
+- }
+-
+- @Override
+- public AllocatedBuffer release() {
+- nettyBuffer.release();
+- return this;
+- }
+- }
+-}
+diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java b/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java
+index c4ca7b9b8c..2ed83a313b 100644
+--- a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java
++++ b/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java
+@@ -26,8 +26,7 @@ import javax.net.ssl.SSLEngine;
+ */
+ @Deprecated
+ public final class JdkAlpnApplicationProtocolNegotiator extends JdkBaseApplicationProtocolNegotiator {
+- private static final boolean AVAILABLE = Conscrypt.isAvailable() ||
+- JdkAlpnSslUtils.supportsAlpn() ||
++ private static final boolean AVAILABLE = JdkAlpnSslUtils.supportsAlpn() ||
+ JettyAlpnSslEngine.isAvailable();
+
+ private static final SslEngineWrapperFactory ALPN_WRAPPER = AVAILABLE ? new AlpnWrapper() : new FailureWrapper();
+@@ -119,7 +118,6 @@ public final class JdkAlpnApplicationProtocolNegotiator extends JdkBaseApplicati
+ public SSLEngine wrapSslEngine(SSLEngine engine, ByteBufAllocator alloc,
+ JdkApplicationProtocolNegotiator applicationNegotiator, boolean isServer) {
+ throw new RuntimeException("ALPN unsupported. Is your classpath configured correctly?"
+- + " For Conscrypt, add the appropriate Conscrypt JAR to classpath and set the security provider."
+ + " For Jetty-ALPN, see "
+ + "http://www.eclipse.org/jetty/documentation/current/alpn-chapter.html#alpn...");
+ }
+@@ -129,10 +127,6 @@ public final class JdkAlpnApplicationProtocolNegotiator extends JdkBaseApplicati
+ @Override
+ public SSLEngine wrapSslEngine(SSLEngine engine, ByteBufAllocator alloc,
+ JdkApplicationProtocolNegotiator applicationNegotiator, boolean isServer) {
+- if (Conscrypt.isEngineSupported(engine)) {
+- return isServer ? ConscryptAlpnSslEngine.newServerEngine(engine, alloc, applicationNegotiator)
+- : ConscryptAlpnSslEngine.newClientEngine(engine, alloc, applicationNegotiator);
+- }
+ // ALPN support was recently backported to Java8 as
+ // https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8230977.
+ // Because of this lets not do a Java version runtime check but just depend on if the required methods are
+diff --git a/handler/src/main/java/io/netty/handler/ssl/SslHandler.java b/handler/src/main/java/io/netty/handler/ssl/SslHandler.java
+index de101967ba..8e11bbf4cc 100644
+--- a/handler/src/main/java/io/netty/handler/ssl/SslHandler.java
++++ b/handler/src/main/java/io/netty/handler/ssl/SslHandler.java
+@@ -228,50 +228,6 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
+ return ((ReferenceCountedOpenSslEngine) engine).jdkCompatibilityMode;
+ }
+ },
+- CONSCRYPT(true, COMPOSITE_CUMULATOR) {
+- @Override
+- SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int len, ByteBuf out)
+- throws SSLException {
+- int nioBufferCount = in.nioBufferCount();
+- int writerIndex = out.writerIndex();
+- final SSLEngineResult result;
+- if (nioBufferCount > 1) {
+- /*
+- * Use a special unwrap method without additional memory copies.
+- */
+- try {
+- handler.singleBuffer[0] = toByteBuffer(out, writerIndex, out.writableBytes());
+- result = ((ConscryptAlpnSslEngine) handler.engine).unwrap(
+- in.nioBuffers(readerIndex, len),
+- handler.singleBuffer);
+- } finally {
+- handler.singleBuffer[0] = null;
+- }
+- } else {
+- result = handler.engine.unwrap(toByteBuffer(in, readerIndex, len),
+- toByteBuffer(out, writerIndex, out.writableBytes()));
+- }
+- out.writerIndex(writerIndex + result.bytesProduced());
+- return result;
+- }
+-
+- @Override
+- ByteBuf allocateWrapBuffer(SslHandler handler, ByteBufAllocator allocator,
+- int pendingBytes, int numComponents) {
+- return allocator.directBuffer(
+- ((ConscryptAlpnSslEngine) handler.engine).calculateOutNetBufSize(pendingBytes, numComponents));
+- }
+-
+- @Override
+- int calculatePendingData(SslHandler handler, int guess) {
+- return guess;
+- }
+-
+- @Override
+- boolean jdkCompatibilityMode(SSLEngine engine) {
+- return true;
+- }
+- },
+ JDK(false, MERGE_CUMULATOR) {
+ @Override
+ SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int len, ByteBuf out)
+@@ -324,8 +280,7 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
+ };
+
+ static SslEngineType forEngine(SSLEngine engine) {
+- return engine instanceof ReferenceCountedOpenSslEngine ? TCNATIVE :
+- engine instanceof ConscryptAlpnSslEngine ? CONSCRYPT : JDK;
++ return engine instanceof ReferenceCountedOpenSslEngine ? TCNATIVE : JDK;
+ }
+
+ SslEngineType(boolean wantsDirectBuffer, Cumulator cumulator) {
+diff --git a/pom.xml b/pom.xml
+index d548aa5513..db3d7b0d38 100644
+--- a/pom.xml
++++ b/pom.xml
+@@ -489,16 +489,6 @@
+ <optional>true</optional>
+ </dependency>
+
+- <!-- Conscrypt - needed for running tests, used for acclerating SSL with OpenSSL. -->
+- <dependency>
+- <groupId>${conscrypt.groupId}</groupId>
+- <artifactId>${conscrypt.artifactId}</artifactId>
+- <classifier>${conscrypt.classifier}</classifier>
+- <version>${conscrypt.version}</version>
+- <scope>compile</scope>
+- <optional>true</optional>
+- </dependency>
+-
+ <!--
+ Bouncy Castle - completely optional, only needed when:
+ - you generate a temporary self-signed certificate using SelfSignedCertificate, and
+--
+2.26.2
+
diff --git a/0003-Remove-conscrypt-ALPN.patch b/0003-Remove-conscrypt-ALPN.patch
deleted file mode 100644
index e71ba5a..0000000
--- a/0003-Remove-conscrypt-ALPN.patch
+++ /dev/null
@@ -1,511 +0,0 @@
-From 039534e20546221c3466d1ceb663625c59edb0e7 Mon Sep 17 00:00:00 2001
-From: Michael Simacek <msimacek(a)redhat.com>
-Date: Tue, 11 Jul 2017 13:37:22 +0200
-Subject: [PATCH 3/3] Remove conscrypt ALPN
-
----
- handler/pom.xml | 6 -
- .../netty/handler/ssl/ConscryptAlpnSslEngine.java | 176 ---------------------
- .../ssl/JdkAlpnApplicationProtocolNegotiator.java | 6 +-
- .../main/java/io/netty/handler/ssl/SslHandler.java | 35 ----
- .../ssl/ConscryptJdkSslEngineInteropTest.java | 76 ---------
- .../io/netty/handler/ssl/Java8SslTestUtils.java | 7 -
- .../ssl/JdkConscryptSslEngineInteropTest.java | 86 ----------
- .../io/netty/handler/ssl/JdkSslEngineTest.java | 2 +-
- 8 files changed, 2 insertions(+), 392 deletions(-)
- delete mode 100644 handler/src/main/java/io/netty/handler/ssl/ConscryptAlpnSslEngine.java
- delete mode 100644 handler/src/test/java/io/netty/handler/ssl/ConscryptJdkSslEngineInteropTest.java
- delete mode 100644 handler/src/test/java/io/netty/handler/ssl/JdkConscryptSslEngineInteropTest.java
-
-diff --git a/handler/pom.xml b/handler/pom.xml
-index 52e63ca..69af32a 100644
---- a/handler/pom.xml
-+++ b/handler/pom.xml
-@@ -60,12 +60,6 @@
- <optional>true</optional>
- </dependency>
- <dependency>
-- <groupId>${conscrypt.groupId}</groupId>
-- <artifactId>${conscrypt.artifactId}</artifactId>
-- <classifier>${conscrypt.classifier}</classifier>
-- <optional>true</optional>
-- </dependency>
-- <dependency>
- <groupId>org.mockito</groupId>
- <artifactId>mockito-core</artifactId>
- </dependency>
-diff --git a/handler/src/main/java/io/netty/handler/ssl/ConscryptAlpnSslEngine.java b/handler/src/main/java/io/netty/handler/ssl/ConscryptAlpnSslEngine.java
-deleted file mode 100644
-index 8e7a544..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/ConscryptAlpnSslEngine.java
-+++ /dev/null
-@@ -1,176 +0,0 @@
--/*
-- * Copyright 2017 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
--
--import static io.netty.handler.ssl.SslUtils.toSSLHandshakeException;
--import static io.netty.util.internal.ObjectUtil.checkNotNull;
--import static java.lang.Math.min;
--
--import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectionListener;
--import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector;
--import java.lang.reflect.Method;
--import java.nio.ByteBuffer;
--import java.util.Collections;
--import java.util.LinkedHashSet;
--import java.util.List;
--import javax.net.ssl.SSLEngine;
--import javax.net.ssl.SSLEngineResult;
--import javax.net.ssl.SSLException;
--
--import io.netty.util.internal.PlatformDependent;
--import org.conscrypt.Conscrypt;
--import org.conscrypt.HandshakeListener;
--
--/**
-- * A {@link JdkSslEngine} that uses the Conscrypt provider or SSL with ALPN.
-- */
--abstract class ConscryptAlpnSslEngine extends JdkSslEngine {
-- private static final Class<?> ENGINES_CLASS = getEnginesClass();
--
-- /**
-- * Indicates whether or not conscrypt is available on the current system.
-- */
-- static boolean isAvailable() {
-- return ENGINES_CLASS != null && PlatformDependent.javaVersion() >= 8;
-- }
--
-- static boolean isEngineSupported(SSLEngine engine) {
-- return isAvailable() && isConscryptEngine(engine, ENGINES_CLASS);
-- }
--
-- static ConscryptAlpnSslEngine newClientEngine(SSLEngine engine,
-- JdkApplicationProtocolNegotiator applicationNegotiator) {
-- return new ClientEngine(engine, applicationNegotiator);
-- }
--
-- static ConscryptAlpnSslEngine newServerEngine(SSLEngine engine,
-- JdkApplicationProtocolNegotiator applicationNegotiator) {
-- return new ServerEngine(engine, applicationNegotiator);
-- }
--
-- private ConscryptAlpnSslEngine(SSLEngine engine, List<String> protocols) {
-- super(engine);
--
-- // Set the list of supported ALPN protocols on the engine.
-- Conscrypt.Engines.setAlpnProtocols(engine, protocols.toArray(new String[protocols.size()]));
-- }
--
-- /**
-- * Calculates the maximum size of the encrypted output buffer required to wrap the given plaintext bytes. Assumes
-- * as a worst case that there is one TLS record per buffer.
-- *
-- * @param plaintextBytes the number of plaintext bytes to be wrapped.
-- * @param numBuffers the number of buffers that the plaintext bytes are spread across.
-- * @return the maximum size of the encrypted output buffer required for the wrap operation.
-- */
-- final int calculateOutNetBufSize(int plaintextBytes, int numBuffers) {
-- // Assuming a max of one frame per component in a composite buffer.
-- long maxOverhead = (long) Conscrypt.Engines.maxSealOverhead(getWrappedEngine()) * numBuffers;
-- // TODO(nmittler): update this to use MAX_ENCRYPTED_PACKET_LENGTH instead of Integer.MAX_VALUE
-- return (int) min(Integer.MAX_VALUE, plaintextBytes + maxOverhead);
-- }
--
-- final SSLEngineResult unwrap(ByteBuffer[] srcs, ByteBuffer[] dests) throws SSLException {
-- return Conscrypt.Engines.unwrap(getWrappedEngine(), srcs, dests);
-- }
--
-- private static final class ClientEngine extends ConscryptAlpnSslEngine {
-- private final ProtocolSelectionListener protocolListener;
--
-- ClientEngine(SSLEngine engine,
-- JdkApplicationProtocolNegotiator applicationNegotiator) {
-- super(engine, applicationNegotiator.protocols());
-- // Register for completion of the handshake.
-- Conscrypt.Engines.setHandshakeListener(engine, new HandshakeListener() {
-- @Override
-- public void onHandshakeFinished() throws SSLException {
-- selectProtocol();
-- }
-- });
--
-- protocolListener = checkNotNull(applicationNegotiator
-- .protocolListenerFactory().newListener(this, applicationNegotiator.protocols()),
-- "protocolListener");
-- }
--
-- private void selectProtocol() throws SSLException {
-- String protocol = Conscrypt.Engines.getAlpnSelectedProtocol(getWrappedEngine());
-- try {
-- protocolListener.selected(protocol);
-- } catch (Throwable e) {
-- throw toSSLHandshakeException(e);
-- }
-- }
-- }
--
-- private static final class ServerEngine extends ConscryptAlpnSslEngine {
-- private final ProtocolSelector protocolSelector;
--
-- ServerEngine(SSLEngine engine, JdkApplicationProtocolNegotiator applicationNegotiator) {
-- super(engine, applicationNegotiator.protocols());
--
-- // Register for completion of the handshake.
-- Conscrypt.Engines.setHandshakeListener(engine, new HandshakeListener() {
-- @Override
-- public void onHandshakeFinished() throws SSLException {
-- selectProtocol();
-- }
-- });
--
-- protocolSelector = checkNotNull(applicationNegotiator.protocolSelectorFactory()
-- .newSelector(this,
-- new LinkedHashSet<String>(applicationNegotiator.protocols())),
-- "protocolSelector");
-- }
--
-- private void selectProtocol() throws SSLException {
-- try {
-- String protocol = Conscrypt.Engines.getAlpnSelectedProtocol(getWrappedEngine());
-- protocolSelector.select(protocol != null ? Collections.singletonList(protocol)
-- : Collections.<String>emptyList());
-- } catch (Throwable e) {
-- throw toSSLHandshakeException(e);
-- }
-- }
-- }
--
-- private static Class<?> getEnginesClass() {
-- try {
-- // Always use bootstrap class loader.
-- Class<?> engineClass = Class.forName("org.conscrypt.Conscrypt$Engines", true,
-- ConscryptAlpnSslEngine.class.getClassLoader());
-- // Ensure that it also has the isConscrypt method.
-- getIsConscryptMethod(engineClass);
-- return engineClass;
-- } catch (Throwable ignore) {
-- // Conscrypt was not loaded.
-- return null;
-- }
-- }
--
-- private static boolean isConscryptEngine(SSLEngine engine, Class<?> enginesClass) {
-- try {
-- Method method = getIsConscryptMethod(enginesClass);
-- return (Boolean) method.invoke(null, engine);
-- } catch (Throwable ignore) {
-- return false;
-- }
-- }
--
-- private static Method getIsConscryptMethod(Class<?> enginesClass) throws NoSuchMethodException {
-- return enginesClass.getMethod("isConscrypt", SSLEngine.class);
-- }
--}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java b/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java
-index f82c7da..9c4ab9e 100644
---- a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java
-+++ b/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java
-@@ -21,7 +21,7 @@ import javax.net.ssl.SSLEngine;
- * The {@link JdkApplicationProtocolNegotiator} to use if you need ALPN and are using {@link SslProvider#JDK}.
- */
- public final class JdkAlpnApplicationProtocolNegotiator extends JdkBaseApplicationProtocolNegotiator {
-- private static final boolean AVAILABLE = ConscryptAlpnSslEngine.isAvailable() || JettyAlpnSslEngine.isAvailable();
-+ private static final boolean AVAILABLE = JettyAlpnSslEngine.isAvailable();
- private static final SslEngineWrapperFactory ALPN_WRAPPER = AVAILABLE ? new AlpnWrapper() : new FailureWrapper();
-
- /**
-@@ -121,10 +121,6 @@ public final class JdkAlpnApplicationProtocolNegotiator extends JdkBaseApplicati
- @Override
- public SSLEngine wrapSslEngine(SSLEngine engine, JdkApplicationProtocolNegotiator applicationNegotiator,
- boolean isServer) {
-- if (ConscryptAlpnSslEngine.isEngineSupported(engine)) {
-- return isServer ? ConscryptAlpnSslEngine.newServerEngine(engine, applicationNegotiator)
-- : ConscryptAlpnSslEngine.newClientEngine(engine, applicationNegotiator);
-- }
- if (JettyAlpnSslEngine.isAvailable()) {
- return isServer ? JettyAlpnSslEngine.newServerEngine(engine, applicationNegotiator)
- : JettyAlpnSslEngine.newClientEngine(engine, applicationNegotiator);
-diff --git a/handler/src/main/java/io/netty/handler/ssl/SslHandler.java b/handler/src/main/java/io/netty/handler/ssl/SslHandler.java
-index 05c451a..8693011 100644
---- a/handler/src/main/java/io/netty/handler/ssl/SslHandler.java
-+++ b/handler/src/main/java/io/netty/handler/ssl/SslHandler.java
-@@ -187,38 +187,6 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
- new ClosedChannelException(), SslHandler.class, "channelInactive(...)");
-
- private enum SslEngineType {
-- CONSCRYPT(true, COMPOSITE_CUMULATOR) {
-- @Override
-- SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int len, ByteBuf out)
-- throws SSLException {
-- int nioBufferCount = in.nioBufferCount();
-- int writerIndex = out.writerIndex();
-- final SSLEngineResult result;
-- if (nioBufferCount > 1) {
-- /*
-- * Use a special unwrap method without additional memory copies.
-- */
-- try {
-- handler.singleBuffer[0] = toByteBuffer(out, writerIndex, out.writableBytes());
-- result = ((ConscryptAlpnSslEngine) handler.engine).unwrap(
-- in.nioBuffers(readerIndex, len),
-- handler.singleBuffer);
-- } finally {
-- handler.singleBuffer[0] = null;
-- }
-- } else {
-- result = handler.engine.unwrap(toByteBuffer(in, readerIndex, len),
-- toByteBuffer(out, writerIndex, out.writableBytes()));
-- }
-- out.writerIndex(writerIndex + result.bytesProduced());
-- return result;
-- }
--
-- @Override
-- int calculateWrapBufferCapacity(SslHandler handler, int pendingBytes, int numComponents) {
-- return ((ConscryptAlpnSslEngine) handler.engine).calculateOutNetBufSize(pendingBytes, numComponents);
-- }
-- },
- JDK(false, MERGE_CUMULATOR) {
- @Override
- SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int len, ByteBuf out)
-@@ -237,9 +205,6 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
- };
-
- static SslEngineType forEngine(SSLEngine engine) {
-- if (engine instanceof ConscryptAlpnSslEngine) {
-- return CONSCRYPT;
-- }
- return JDK;
- }
-
-diff --git a/handler/src/test/java/io/netty/handler/ssl/ConscryptJdkSslEngineInteropTest.java b/handler/src/test/java/io/netty/handler/ssl/ConscryptJdkSslEngineInteropTest.java
-deleted file mode 100644
-index e217136..0000000
---- a/handler/src/test/java/io/netty/handler/ssl/ConscryptJdkSslEngineInteropTest.java
-+++ /dev/null
-@@ -1,76 +0,0 @@
--/*
-- * Copyright 2016 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
--
--import java.security.Provider;
--import org.junit.BeforeClass;
--import org.junit.Ignore;
--
--import org.junit.runner.RunWith;
--import org.junit.runners.Parameterized;
--
--import java.util.ArrayList;
--import java.util.Collection;
--import java.util.List;
--
--import static org.junit.Assume.assumeTrue;
--
--(a)RunWith(Parameterized.class)
--public class ConscryptJdkSslEngineInteropTest extends SSLEngineTest {
--
-- @Parameterized.Parameters(name = "{index}: bufferType = {0}")
-- public static Collection<Object> data() {
-- List<Object> params = new ArrayList<Object>();
-- for (BufferType type: BufferType.values()) {
-- params.add(type);
-- }
-- return params;
-- }
--
-- public ConscryptJdkSslEngineInteropTest(BufferType type) {
-- super(type);
-- }
--
-- @BeforeClass
-- public static void checkConscrypt() {
-- assumeTrue(ConscryptAlpnSslEngine.isAvailable());
-- }
--
-- @Override
-- protected SslProvider sslClientProvider() {
-- return SslProvider.JDK;
-- }
--
-- @Override
-- protected SslProvider sslServerProvider() {
-- return SslProvider.JDK;
-- }
--
-- @Override
-- protected Provider clientSslContextProvider() {
-- return Java8SslTestUtils.conscryptProvider();
-- }
--
-- @Ignore /* Does the JDK support a "max certificate chain length"? */
-- @Override
-- public void testMutualAuthValidClientCertChainTooLongFailOptionalClientAuth() throws Exception {
-- }
--
-- @Ignore /* Does the JDK support a "max certificate chain length"? */
-- @Override
-- public void testMutualAuthValidClientCertChainTooLongFailRequireClientAuth() throws Exception {
-- }
--}
-diff --git a/handler/src/test/java/io/netty/handler/ssl/Java8SslTestUtils.java b/handler/src/test/java/io/netty/handler/ssl/Java8SslTestUtils.java
-index cc2e6c6..f9cf771 100644
---- a/handler/src/test/java/io/netty/handler/ssl/Java8SslTestUtils.java
-+++ b/handler/src/test/java/io/netty/handler/ssl/Java8SslTestUtils.java
-@@ -16,12 +16,9 @@
-
- package io.netty.handler.ssl;
-
--import org.conscrypt.OpenSSLProvider;
--
- import javax.net.ssl.SNIMatcher;
- import javax.net.ssl.SNIServerName;
- import javax.net.ssl.SSLParameters;
--import java.security.Provider;
- import java.util.Collections;
-
- final class Java8SslTestUtils {
-@@ -37,8 +34,4 @@ final class Java8SslTestUtils {
- };
- parameters.setSNIMatchers(Collections.singleton(matcher));
- }
--
-- static Provider conscryptProvider() {
-- return new OpenSSLProvider();
-- }
- }
-diff --git a/handler/src/test/java/io/netty/handler/ssl/JdkConscryptSslEngineInteropTest.java b/handler/src/test/java/io/netty/handler/ssl/JdkConscryptSslEngineInteropTest.java
-deleted file mode 100644
-index 0625f7a..0000000
---- a/handler/src/test/java/io/netty/handler/ssl/JdkConscryptSslEngineInteropTest.java
-+++ /dev/null
-@@ -1,86 +0,0 @@
--/*
-- * Copyright 2017 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
--
--import java.security.Provider;
--import org.junit.BeforeClass;
--import org.junit.Ignore;
--import org.junit.Test;
--import org.junit.runner.RunWith;
--import org.junit.runners.Parameterized;
--
--import java.util.ArrayList;
--import java.util.Collection;
--import java.util.List;
--
--import static org.junit.Assume.assumeTrue;
--
--(a)RunWith(Parameterized.class)
--public class JdkConscryptSslEngineInteropTest extends SSLEngineTest {
--
-- @Parameterized.Parameters(name = "{index}: bufferType = {0}")
-- public static Collection<Object> data() {
-- List<Object> params = new ArrayList<Object>();
-- for (BufferType type: BufferType.values()) {
-- params.add(type);
-- }
-- return params;
-- }
--
-- public JdkConscryptSslEngineInteropTest(BufferType type) {
-- super(type);
-- }
--
-- @BeforeClass
-- public static void checkConscrypt() {
-- assumeTrue(ConscryptAlpnSslEngine.isAvailable());
-- }
--
-- @Override
-- protected SslProvider sslClientProvider() {
-- return SslProvider.JDK;
-- }
--
-- @Override
-- protected SslProvider sslServerProvider() {
-- return SslProvider.JDK;
-- }
--
-- @Override
-- protected Provider serverSslContextProvider() {
-- return Java8SslTestUtils.conscryptProvider();
-- }
--
-- @Override
-- @Test
-- @Ignore("TODO: Make this work with Conscrypt")
-- public void testMutualAuthValidClientCertChainTooLongFailOptionalClientAuth() throws Exception {
-- super.testMutualAuthValidClientCertChainTooLongFailOptionalClientAuth();
-- }
--
-- @Override
-- @Test
-- @Ignore("TODO: Make this work with Conscrypt")
-- public void testMutualAuthValidClientCertChainTooLongFailRequireClientAuth() throws Exception {
-- super.testMutualAuthValidClientCertChainTooLongFailRequireClientAuth();
-- }
--
-- @Override
-- protected boolean mySetupMutualAuthServerIsValidClientException(Throwable cause) {
-- // TODO(scott): work around for a JDK issue. The exception should be SSLHandshakeException.
-- return super.mySetupMutualAuthServerIsValidClientException(cause) || causedBySSLException(cause);
-- }
--}
-diff --git a/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java b/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java
-index 4489b16..e32fa0d 100644
---- a/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java
-+++ b/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java
-@@ -81,7 +81,7 @@ public class JdkSslEngineTest extends SSLEngineTest {
-
- @Override
- boolean isAvailable() {
-- return ConscryptAlpnSslEngine.isAvailable();
-+ return false;
- }
-
- @Override
---
-2.9.4
-
diff --git a/0003-Remove-optional-deps-jetty-alpn-and-npn.patch b/0003-Remove-optional-deps-jetty-alpn-and-npn.patch
new file mode 100644
index 0000000..6e74960
--- /dev/null
+++ b/0003-Remove-optional-deps-jetty-alpn-and-npn.patch
@@ -0,0 +1,405 @@
+From cb6b51eed1faef580120e19aa1b5404c19a9398b Mon Sep 17 00:00:00 2001
+From: Mat Booth <mat.booth(a)redhat.com>
+Date: Mon, 7 Sep 2020 13:26:20 +0100
+Subject: [PATCH 3/5] Remove optional deps jetty alpn and npn
+
+---
+ handler/pom.xml | 10 --
+ .../JdkAlpnApplicationProtocolNegotiator.java | 7 +-
+ .../JdkNpnApplicationProtocolNegotiator.java | 10 +-
+ .../netty/handler/ssl/JettyAlpnSslEngine.java | 157 ------------------
+ .../netty/handler/ssl/JettyNpnSslEngine.java | 122 --------------
+ pom.xml | 14 --
+ 6 files changed, 3 insertions(+), 317 deletions(-)
+ delete mode 100644 handler/src/main/java/io/netty/handler/ssl/JettyAlpnSslEngine.java
+ delete mode 100644 handler/src/main/java/io/netty/handler/ssl/JettyNpnSslEngine.java
+
+diff --git a/handler/pom.xml b/handler/pom.xml
+index 378aeda2fe..be8206dc89 100644
+--- a/handler/pom.xml
++++ b/handler/pom.xml
+@@ -71,16 +71,6 @@
+ <artifactId>bcpkix-jdk15on</artifactId>
+ <optional>true</optional>
+ </dependency>
+- <dependency>
+- <groupId>org.eclipse.jetty.npn</groupId>
+- <artifactId>npn-api</artifactId>
+- <optional>true</optional>
+- </dependency>
+- <dependency>
+- <groupId>org.eclipse.jetty.alpn</groupId>
+- <artifactId>alpn-api</artifactId>
+- <optional>true</optional>
+- </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-core</artifactId>
+diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java b/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java
+index 2ed83a313b..dbd5ed9f07 100644
+--- a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java
++++ b/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java
+@@ -26,8 +26,7 @@ import javax.net.ssl.SSLEngine;
+ */
+ @Deprecated
+ public final class JdkAlpnApplicationProtocolNegotiator extends JdkBaseApplicationProtocolNegotiator {
+- private static final boolean AVAILABLE = JdkAlpnSslUtils.supportsAlpn() ||
+- JettyAlpnSslEngine.isAvailable();
++ private static final boolean AVAILABLE = JdkAlpnSslUtils.supportsAlpn();
+
+ private static final SslEngineWrapperFactory ALPN_WRAPPER = AVAILABLE ? new AlpnWrapper() : new FailureWrapper();
+
+@@ -134,10 +133,6 @@ public final class JdkAlpnApplicationProtocolNegotiator extends JdkBaseApplicati
+ if (JdkAlpnSslUtils.supportsAlpn()) {
+ return new JdkAlpnSslEngine(engine, applicationNegotiator, isServer);
+ }
+- if (JettyAlpnSslEngine.isAvailable()) {
+- return isServer ? JettyAlpnSslEngine.newServerEngine(engine, applicationNegotiator)
+- : JettyAlpnSslEngine.newClientEngine(engine, applicationNegotiator);
+- }
+ throw new UnsupportedOperationException("ALPN not supported. Unable to wrap SSLEngine of type '"
+ + engine.getClass().getName() + "')");
+ }
+diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java b/handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java
+index 3c2863b66c..2703336e8b 100644
+--- a/handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java
++++ b/handler/src/main/java/io/netty/handler/ssl/JdkNpnApplicationProtocolNegotiator.java
+@@ -25,17 +25,11 @@ import javax.net.ssl.SSLEngine;
+ @Deprecated
+ public final class JdkNpnApplicationProtocolNegotiator extends JdkBaseApplicationProtocolNegotiator {
+ private static final SslEngineWrapperFactory NPN_WRAPPER = new SslEngineWrapperFactory() {
+- {
+- if (!JettyNpnSslEngine.isAvailable()) {
+- throw new RuntimeException("NPN unsupported. Is your classpath configured correctly?"
+- + " See https://wiki.eclipse.org/Jetty/Feature/NPN");
+- }
+- }
+-
+ @Override
+ public SSLEngine wrapSslEngine(SSLEngine engine,
+ JdkApplicationProtocolNegotiator applicationNegotiator, boolean isServer) {
+- return new JettyNpnSslEngine(engine, applicationNegotiator, isServer);
++ throw new UnsupportedOperationException("NPN not supported. Unable to wrap SSLEngine of type '"
++ + engine.getClass().getName() + "')");
+ }
+ };
+
+diff --git a/handler/src/main/java/io/netty/handler/ssl/JettyAlpnSslEngine.java b/handler/src/main/java/io/netty/handler/ssl/JettyAlpnSslEngine.java
+deleted file mode 100644
+index ce9f14a57e..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/JettyAlpnSslEngine.java
++++ /dev/null
+@@ -1,157 +0,0 @@
+-/*
+- * Copyright 2014 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- * http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-package io.netty.handler.ssl;
+-
+-import static io.netty.handler.ssl.SslUtils.toSSLHandshakeException;
+-import static io.netty.util.internal.ObjectUtil.checkNotNull;
+-
+-import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectionListener;
+-import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector;
+-
+-import java.util.LinkedHashSet;
+-import java.util.List;
+-
+-import javax.net.ssl.SSLEngine;
+-import javax.net.ssl.SSLException;
+-
+-import io.netty.util.internal.PlatformDependent;
+-import org.eclipse.jetty.alpn.ALPN;
+-
+-abstract class JettyAlpnSslEngine extends JdkSslEngine {
+- private static final boolean available = initAvailable();
+-
+- static boolean isAvailable() {
+- return available;
+- }
+-
+- private static boolean initAvailable() {
+- if (PlatformDependent.javaVersion() <= 8) {
+- try {
+- // Always use bootstrap class loader.
+- Class.forName("sun.security.ssl.ALPNExtension", true, null);
+- return true;
+- } catch (Throwable ignore) {
+- // alpn-boot was not loaded.
+- }
+- }
+- return false;
+- }
+-
+- static JettyAlpnSslEngine newClientEngine(SSLEngine engine,
+- JdkApplicationProtocolNegotiator applicationNegotiator) {
+- return new ClientEngine(engine, applicationNegotiator);
+- }
+-
+- static JettyAlpnSslEngine newServerEngine(SSLEngine engine,
+- JdkApplicationProtocolNegotiator applicationNegotiator) {
+- return new ServerEngine(engine, applicationNegotiator);
+- }
+-
+- private JettyAlpnSslEngine(SSLEngine engine) {
+- super(engine);
+- }
+-
+- private static final class ClientEngine extends JettyAlpnSslEngine {
+- ClientEngine(SSLEngine engine, final JdkApplicationProtocolNegotiator applicationNegotiator) {
+- super(engine);
+- checkNotNull(applicationNegotiator, "applicationNegotiator");
+- final ProtocolSelectionListener protocolListener = checkNotNull(applicationNegotiator
+- .protocolListenerFactory().newListener(this, applicationNegotiator.protocols()),
+- "protocolListener");
+- ALPN.put(engine, new ALPN.ClientProvider() {
+- @Override
+- public List<String> protocols() {
+- return applicationNegotiator.protocols();
+- }
+-
+- @Override
+- public void selected(String protocol) throws SSLException {
+- try {
+- protocolListener.selected(protocol);
+- } catch (Throwable t) {
+- throw toSSLHandshakeException(t);
+- }
+- }
+-
+- @Override
+- public void unsupported() {
+- protocolListener.unsupported();
+- }
+- });
+- }
+-
+- @Override
+- public void closeInbound() throws SSLException {
+- try {
+- ALPN.remove(getWrappedEngine());
+- } finally {
+- super.closeInbound();
+- }
+- }
+-
+- @Override
+- public void closeOutbound() {
+- try {
+- ALPN.remove(getWrappedEngine());
+- } finally {
+- super.closeOutbound();
+- }
+- }
+- }
+-
+- private static final class ServerEngine extends JettyAlpnSslEngine {
+- ServerEngine(SSLEngine engine, final JdkApplicationProtocolNegotiator applicationNegotiator) {
+- super(engine);
+- checkNotNull(applicationNegotiator, "applicationNegotiator");
+- final ProtocolSelector protocolSelector = checkNotNull(applicationNegotiator.protocolSelectorFactory()
+- .newSelector(this, new LinkedHashSet<String>(applicationNegotiator.protocols())),
+- "protocolSelector");
+- ALPN.put(engine, new ALPN.ServerProvider() {
+- @Override
+- public String select(List<String> protocols) throws SSLException {
+- try {
+- return protocolSelector.select(protocols);
+- } catch (Throwable t) {
+- throw toSSLHandshakeException(t);
+- }
+- }
+-
+- @Override
+- public void unsupported() {
+- protocolSelector.unsupported();
+- }
+- });
+- }
+-
+- @Override
+- public void closeInbound() throws SSLException {
+- try {
+- ALPN.remove(getWrappedEngine());
+- } finally {
+- super.closeInbound();
+- }
+- }
+-
+- @Override
+- public void closeOutbound() {
+- try {
+- ALPN.remove(getWrappedEngine());
+- } finally {
+- super.closeOutbound();
+- }
+- }
+- }
+-}
+diff --git a/handler/src/main/java/io/netty/handler/ssl/JettyNpnSslEngine.java b/handler/src/main/java/io/netty/handler/ssl/JettyNpnSslEngine.java
+deleted file mode 100644
+index 77e7366e53..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/JettyNpnSslEngine.java
++++ /dev/null
+@@ -1,122 +0,0 @@
+-/*
+- * Copyright 2014 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- * http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-
+-package io.netty.handler.ssl;
+-
+-import static io.netty.util.internal.ObjectUtil.checkNotNull;
+-import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectionListener;
+-import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector;
+-import io.netty.util.internal.PlatformDependent;
+-
+-import java.util.LinkedHashSet;
+-import java.util.List;
+-
+-import javax.net.ssl.SSLEngine;
+-import javax.net.ssl.SSLException;
+-
+-import org.eclipse.jetty.npn.NextProtoNego;
+-import org.eclipse.jetty.npn.NextProtoNego.ClientProvider;
+-import org.eclipse.jetty.npn.NextProtoNego.ServerProvider;
+-
+-final class JettyNpnSslEngine extends JdkSslEngine {
+- private static boolean available;
+-
+- static boolean isAvailable() {
+- updateAvailability();
+- return available;
+- }
+-
+- private static void updateAvailability() {
+- if (available) {
+- return;
+- }
+- try {
+- // Always use bootstrap class loader.
+- Class.forName("sun.security.ssl.NextProtoNegoExtension", true, null);
+- available = true;
+- } catch (Exception ignore) {
+- // npn-boot was not loaded.
+- }
+- }
+-
+- JettyNpnSslEngine(SSLEngine engine, final JdkApplicationProtocolNegotiator applicationNegotiator, boolean server) {
+- super(engine);
+- checkNotNull(applicationNegotiator, "applicationNegotiator");
+-
+- if (server) {
+- final ProtocolSelectionListener protocolListener = checkNotNull(applicationNegotiator
+- .protocolListenerFactory().newListener(this, applicationNegotiator.protocols()),
+- "protocolListener");
+- NextProtoNego.put(engine, new ServerProvider() {
+- @Override
+- public void unsupported() {
+- protocolListener.unsupported();
+- }
+-
+- @Override
+- public List<String> protocols() {
+- return applicationNegotiator.protocols();
+- }
+-
+- @Override
+- public void protocolSelected(String protocol) {
+- try {
+- protocolListener.selected(protocol);
+- } catch (Throwable t) {
+- PlatformDependent.throwException(t);
+- }
+- }
+- });
+- } else {
+- final ProtocolSelector protocolSelector = checkNotNull(applicationNegotiator.protocolSelectorFactory()
+- .newSelector(this, new LinkedHashSet<String>(applicationNegotiator.protocols())),
+- "protocolSelector");
+- NextProtoNego.put(engine, new ClientProvider() {
+- @Override
+- public boolean supports() {
+- return true;
+- }
+-
+- @Override
+- public void unsupported() {
+- protocolSelector.unsupported();
+- }
+-
+- @Override
+- public String selectProtocol(List<String> protocols) {
+- try {
+- return protocolSelector.select(protocols);
+- } catch (Throwable t) {
+- PlatformDependent.throwException(t);
+- return null;
+- }
+- }
+- });
+- }
+- }
+-
+- @Override
+- public void closeInbound() throws SSLException {
+- NextProtoNego.remove(getWrappedEngine());
+- super.closeInbound();
+- }
+-
+- @Override
+- public void closeOutbound() {
+- NextProtoNego.remove(getWrappedEngine());
+- super.closeOutbound();
+- }
+-}
+diff --git a/pom.xml b/pom.xml
+index db3d7b0d38..bedd6d6903 100644
+--- a/pom.xml
++++ b/pom.xml
+@@ -453,20 +453,6 @@
+ <optional>true</optional>
+ </dependency>
+
+- <!-- SPDY and HTTP/2 - completely optional -->
+- <dependency>
+- <groupId>org.eclipse.jetty.npn</groupId>
+- <artifactId>npn-api</artifactId>
+- <version>1.1.1.v20141010</version>
+- <scope>provided</scope> <!-- Provided by npn-boot -->
+- </dependency>
+- <dependency>
+- <groupId>org.eclipse.jetty.alpn</groupId>
+- <artifactId>alpn-api</artifactId>
+- <version>1.1.2.v20150522</version>
+- <scope>provided</scope> <!-- Provided by alpn-boot -->
+- </dependency>
+-
+ <!-- Google Protocol Buffers - completely optional -->
+ <dependency>
+ <groupId>com.google.protobuf</groupId>
+--
+2.26.2
+
diff --git a/0004-Remove-jetty-ALPN.patch b/0004-Remove-jetty-ALPN.patch
deleted file mode 100644
index 42b5415..0000000
--- a/0004-Remove-jetty-ALPN.patch
+++ /dev/null
@@ -1,217 +0,0 @@
-diff --git a/handler/pom.xml b/handler/pom.xml
-index 69af32a..b9e5596 100644
---- a/handler/pom.xml
-+++ b/handler/pom.xml
-@@ -54,11 +54,6 @@
- <artifactId>bcpkix-jdk15on</artifactId>
- <optional>true</optional>
- </dependency>
-- <dependency>
-- <groupId>org.eclipse.jetty.alpn</groupId>
-- <artifactId>alpn-api</artifactId>
-- <optional>true</optional>
-- </dependency>
- <dependency>
- <groupId>org.mockito</groupId>
- <artifactId>mockito-core</artifactId>
-diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java b/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java
-index 9c4ab9e..5cc1ab7 100644
---- a/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java
-+++ b/handler/src/main/java/io/netty/handler/ssl/JdkAlpnApplicationProtocolNegotiator.java
-@@ -21,7 +21,7 @@ import javax.net.ssl.SSLEngine;
- * The {@link JdkApplicationProtocolNegotiator} to use if you need ALPN and are using {@link SslProvider#JDK}.
- */
- public final class JdkAlpnApplicationProtocolNegotiator extends JdkBaseApplicationProtocolNegotiator {
-- private static final boolean AVAILABLE = JettyAlpnSslEngine.isAvailable();
-+ private static final boolean AVAILABLE = false;
- private static final SslEngineWrapperFactory ALPN_WRAPPER = AVAILABLE ? new AlpnWrapper() : new FailureWrapper();
-
- /**
-@@ -121,10 +121,6 @@ public final class JdkAlpnApplicationProtocolNegotiator extends JdkBaseApplicati
- @Override
- public SSLEngine wrapSslEngine(SSLEngine engine, JdkApplicationProtocolNegotiator applicationNegotiator,
- boolean isServer) {
-- if (JettyAlpnSslEngine.isAvailable()) {
-- return isServer ? JettyAlpnSslEngine.newServerEngine(engine, applicationNegotiator)
-- : JettyAlpnSslEngine.newClientEngine(engine, applicationNegotiator);
-- }
- throw new RuntimeException("Unable to wrap SSLEngine of type " + engine.getClass().getName());
- }
- }
-diff --git a/handler/src/main/java/io/netty/handler/ssl/JettyAlpnSslEngine.java b/handler/src/main/java/io/netty/handler/ssl/JettyAlpnSslEngine.java
-deleted file mode 100644
-index 624719a..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/JettyAlpnSslEngine.java
-+++ /dev/null
-@@ -1,158 +0,0 @@
--/*
-- * Copyright 2014 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
--
--import static io.netty.handler.ssl.SslUtils.toSSLHandshakeException;
--import static io.netty.util.internal.ObjectUtil.checkNotNull;
--
--import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectionListener;
--import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector;
--
--import java.util.LinkedHashSet;
--import java.util.List;
--
--import javax.net.ssl.SSLEngine;
--import javax.net.ssl.SSLException;
--
--import io.netty.util.internal.PlatformDependent;
--import org.eclipse.jetty.alpn.ALPN;
--
--abstract class JettyAlpnSslEngine extends JdkSslEngine {
-- private static final boolean available = initAvailable();
--
-- static boolean isAvailable() {
-- return available;
-- }
--
-- private static boolean initAvailable() {
-- // TODO: Add support for ALPN when using Java9 and still be able to configure it the Netty way.
-- if (PlatformDependent.javaVersion() <= 8) {
-- try {
-- // Always use bootstrap class loader.
-- Class.forName("sun.security.ssl.ALPNExtension", true, null);
-- return true;
-- } catch (Throwable ignore) {
-- // alpn-boot was not loaded.
-- }
-- }
-- return false;
-- }
--
-- static JettyAlpnSslEngine newClientEngine(SSLEngine engine,
-- JdkApplicationProtocolNegotiator applicationNegotiator) {
-- return new ClientEngine(engine, applicationNegotiator);
-- }
--
-- static JettyAlpnSslEngine newServerEngine(SSLEngine engine,
-- JdkApplicationProtocolNegotiator applicationNegotiator) {
-- return new ServerEngine(engine, applicationNegotiator);
-- }
--
-- private JettyAlpnSslEngine(SSLEngine engine) {
-- super(engine);
-- }
--
-- private static final class ClientEngine extends JettyAlpnSslEngine {
-- ClientEngine(SSLEngine engine, final JdkApplicationProtocolNegotiator applicationNegotiator) {
-- super(engine);
-- checkNotNull(applicationNegotiator, "applicationNegotiator");
-- final ProtocolSelectionListener protocolListener = checkNotNull(applicationNegotiator
-- .protocolListenerFactory().newListener(this, applicationNegotiator.protocols()),
-- "protocolListener");
-- ALPN.put(engine, new ALPN.ClientProvider() {
-- @Override
-- public List<String> protocols() {
-- return applicationNegotiator.protocols();
-- }
--
-- @Override
-- public void selected(String protocol) throws SSLException {
-- try {
-- protocolListener.selected(protocol);
-- } catch (Throwable t) {
-- throw toSSLHandshakeException(t);
-- }
-- }
--
-- @Override
-- public void unsupported() {
-- protocolListener.unsupported();
-- }
-- });
-- }
--
-- @Override
-- public void closeInbound() throws SSLException {
-- try {
-- ALPN.remove(getWrappedEngine());
-- } finally {
-- super.closeInbound();
-- }
-- }
--
-- @Override
-- public void closeOutbound() {
-- try {
-- ALPN.remove(getWrappedEngine());
-- } finally {
-- super.closeOutbound();
-- }
-- }
-- }
--
-- private static final class ServerEngine extends JettyAlpnSslEngine {
-- ServerEngine(SSLEngine engine, final JdkApplicationProtocolNegotiator applicationNegotiator) {
-- super(engine);
-- checkNotNull(applicationNegotiator, "applicationNegotiator");
-- final ProtocolSelector protocolSelector = checkNotNull(applicationNegotiator.protocolSelectorFactory()
-- .newSelector(this, new LinkedHashSet<String>(applicationNegotiator.protocols())),
-- "protocolSelector");
-- ALPN.put(engine, new ALPN.ServerProvider() {
-- @Override
-- public String select(List<String> protocols) throws SSLException {
-- try {
-- return protocolSelector.select(protocols);
-- } catch (Throwable t) {
-- throw toSSLHandshakeException(t);
-- }
-- }
--
-- @Override
-- public void unsupported() {
-- protocolSelector.unsupported();
-- }
-- });
-- }
--
-- @Override
-- public void closeInbound() throws SSLException {
-- try {
-- ALPN.remove(getWrappedEngine());
-- } finally {
-- super.closeInbound();
-- }
-- }
--
-- @Override
-- public void closeOutbound() {
-- try {
-- ALPN.remove(getWrappedEngine());
-- } finally {
-- super.closeOutbound();
-- }
-- }
-- }
--}
-diff --git a/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java b/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java
-index e32fa0d..a8014e5 100644
---- a/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java
-+++ b/handler/src/test/java/io/netty/handler/ssl/JdkSslEngineTest.java
-@@ -62,7 +62,7 @@ public class JdkSslEngineTest extends SSLEngineTest {
- ALPN_DEFAULT {
- @Override
- boolean isAvailable() {
-- return JettyAlpnSslEngine.isAvailable();
-+ return false;
- }
-
- @Override
diff --git a/0001-Remove-OpenSSL-parts-depending-on-tcnative.patch b/0004-Remove-optional-dep-tcnative.patch
similarity index 54%
rename from 0001-Remove-OpenSSL-parts-depending-on-tcnative.patch
rename to 0004-Remove-optional-dep-tcnative.patch
index aee0650..6ed11bd 100644
--- a/0001-Remove-OpenSSL-parts-depending-on-tcnative.patch
+++ b/0004-Remove-optional-dep-tcnative.patch
@@ -1,108 +1,94 @@
-From 39b320920d3473d8cbc94d4a35dad37fa236e278 Mon Sep 17 00:00:00 2001
-From: Severin Gehwolf <sgehwolf(a)redhat.com>
-Date: Thu, 20 Oct 2016 15:54:52 +0200
-Subject: [PATCH 1/3] Remove OpenSSL parts depending on tcnative.
+From c60f3b8d7ca0575bba15682a329dced786f898da Mon Sep 17 00:00:00 2001
+From: Mat Booth <mat.booth(a)redhat.com>
+Date: Mon, 7 Sep 2020 13:41:44 +0100
+Subject: [PATCH 4/5] Remove optional dep tcnative
---
- handler/pom.xml | 6 -
- .../main/java/io/netty/handler/ssl/OpenSsl.java | 503 -----
- .../handler/ssl/OpenSslCertificateException.java | 79 -
- .../io/netty/handler/ssl/OpenSslClientContext.java | 211 --
- .../java/io/netty/handler/ssl/OpenSslContext.java | 58 -
- .../java/io/netty/handler/ssl/OpenSslEngine.java | 40 -
- .../io/netty/handler/ssl/OpenSslEngineMap.java | 35 -
- .../ssl/OpenSslExtendedKeyMaterialManager.java | 40 -
- .../handler/ssl/OpenSslKeyMaterialManager.java | 179 --
- .../io/netty/handler/ssl/OpenSslServerContext.java | 373 ----
- .../handler/ssl/OpenSslServerSessionContext.java | 124 --
- .../netty/handler/ssl/OpenSslSessionContext.java | 137 --
- .../io/netty/handler/ssl/OpenSslSessionStats.java | 253 ---
- .../netty/handler/ssl/OpenSslSessionTicketKey.java | 78 -
- .../ssl/ReferenceCountedOpenSslClientContext.java | 298 ---
- .../ssl/ReferenceCountedOpenSslContext.java | 867 ---------
- .../handler/ssl/ReferenceCountedOpenSslEngine.java | 2037 --------------------
- .../ssl/ReferenceCountedOpenSslServerContext.java | 239 ---
- .../main/java/io/netty/handler/ssl/SslContext.java | 30 +-
- .../main/java/io/netty/handler/ssl/SslHandler.java | 47 +-
- .../netty/handler/ssl/ocsp/OcspClientHandler.java | 65 -
- .../io/netty/handler/ssl/ocsp/package-info.java | 23 -
- .../handler/ssl/JdkOpenSslEngineInteroptTest.java | 108 --
- .../ssl/OpenSslCertificateExceptionTest.java | 49 -
- .../handler/ssl/OpenSslClientContextTest.java | 38 -
- .../io/netty/handler/ssl/OpenSslEngineTest.java | 661 -------
- .../ssl/OpenSslJdkSslEngineInteroptTest.java | 114 --
- .../ssl/OpenSslRenegotiateSmallBIOTest.java | 23 -
- .../netty/handler/ssl/OpenSslRenegotiateTest.java | 36 -
- .../handler/ssl/OpenSslServerContextTest.java | 39 -
- .../io/netty/handler/ssl/OpenSslTestUtils.java | 27 -
- .../java/io/netty/handler/ssl/PemEncodedTest.java | 95 -
- .../ssl/ReferenceCountedOpenSslEngineTest.java | 57 -
- .../java/io/netty/handler/ssl/SniClientTest.java | 161 --
- .../java/io/netty/handler/ssl/SniHandlerTest.java | 496 -----
- .../netty/handler/ssl/SslContextBuilderTest.java | 132 --
- .../java/io/netty/handler/ssl/SslErrorTest.java | 255 ---
- .../java/io/netty/handler/ssl/SslHandlerTest.java | 58 +-
- .../java/io/netty/handler/ssl/ocsp/OcspTest.java | 501 -----
- 39 files changed, 10 insertions(+), 8562 deletions(-)
+ handler/pom.xml | 6 -
+ .../handler/ssl/CipherSuiteConverter.java | 494 ----
+ .../ssl/DefaultOpenSslKeyMaterial.java | 126 -
+ .../java/io/netty/handler/ssl/OpenSsl.java | 610 ----
+ .../OpenSslCachingKeyMaterialProvider.java | 79 -
+ .../OpenSslCachingX509KeyManagerFactory.java | 81 -
+ .../ssl/OpenSslCertificateException.java | 81 -
+ .../handler/ssl/OpenSslClientContext.java | 208 --
+ .../io/netty/handler/ssl/OpenSslContext.java | 58 -
+ .../io/netty/handler/ssl/OpenSslEngine.java | 41 -
+ .../netty/handler/ssl/OpenSslEngineMap.java | 35 -
+ .../ssl/OpenSslKeyMaterialManager.java | 127 -
+ .../ssl/OpenSslKeyMaterialProvider.java | 154 -
+ .../netty/handler/ssl/OpenSslPrivateKey.java | 191 --
+ .../handler/ssl/OpenSslPrivateKeyMethod.java | 62 -
+ .../handler/ssl/OpenSslServerContext.java | 367 ---
+ .../ssl/OpenSslServerSessionContext.java | 124 -
+ .../handler/ssl/OpenSslSessionContext.java | 158 --
+ .../handler/ssl/OpenSslSessionStats.java | 253 --
+ .../handler/ssl/OpenSslSessionTicketKey.java | 78 -
+ ...OpenSslTlsv13X509ExtendedTrustManager.java | 240 --
+ .../ssl/OpenSslX509KeyManagerFactory.java | 413 ---
+ .../ReferenceCountedOpenSslClientContext.java | 343 ---
+ .../ssl/ReferenceCountedOpenSslContext.java | 968 -------
+ .../ssl/ReferenceCountedOpenSslEngine.java | 2467 -----------------
+ .../ReferenceCountedOpenSslServerContext.java | 286 --
+ .../java/io/netty/handler/ssl/SslContext.java | 30 +-
+ .../java/io/netty/handler/ssl/SslHandler.java | 49 +-
+ .../handler/ssl/SslMasterKeyHandler.java | 3 -
+ .../io/netty/handler/ssl/SslProvider.java | 14 +-
+ .../handler/ssl/ocsp/OcspClientHandler.java | 61 -
+ .../netty/handler/ssl/ocsp/package-info.java | 23 -
+ pom.xml | 10 -
+ 33 files changed, 3 insertions(+), 8237 deletions(-)
+ delete mode 100644 handler/src/main/java/io/netty/handler/ssl/CipherSuiteConverter.java
+ delete mode 100644 handler/src/main/java/io/netty/handler/ssl/DefaultOpenSslKeyMaterial.java
delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSsl.java
+ delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslCachingKeyMaterialProvider.java
+ delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslCachingX509KeyManagerFactory.java
delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslCertificateException.java
delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslClientContext.java
delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslContext.java
delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslEngine.java
delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslEngineMap.java
- delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslExtendedKeyMaterialManager.java
delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialManager.java
+ delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialProvider.java
+ delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslPrivateKey.java
+ delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslPrivateKeyMethod.java
delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslServerContext.java
delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslServerSessionContext.java
delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslSessionContext.java
delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslSessionStats.java
delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslSessionTicketKey.java
+ delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslTlsv13X509ExtendedTrustManager.java
+ delete mode 100644 handler/src/main/java/io/netty/handler/ssl/OpenSslX509KeyManagerFactory.java
delete mode 100644 handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslClientContext.java
delete mode 100644 handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslContext.java
delete mode 100644 handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngine.java
delete mode 100644 handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslServerContext.java
delete mode 100644 handler/src/main/java/io/netty/handler/ssl/ocsp/OcspClientHandler.java
delete mode 100644 handler/src/main/java/io/netty/handler/ssl/ocsp/package-info.java
- delete mode 100644 handler/src/test/java/io/netty/handler/ssl/JdkOpenSslEngineInteroptTest.java
- delete mode 100644 handler/src/test/java/io/netty/handler/ssl/OpenSslCertificateExceptionTest.java
- delete mode 100644 handler/src/test/java/io/netty/handler/ssl/OpenSslClientContextTest.java
- delete mode 100644 handler/src/test/java/io/netty/handler/ssl/OpenSslEngineTest.java
- delete mode 100644 handler/src/test/java/io/netty/handler/ssl/OpenSslJdkSslEngineInteroptTest.java
- delete mode 100644 handler/src/test/java/io/netty/handler/ssl/OpenSslRenegotiateSmallBIOTest.java
- delete mode 100644 handler/src/test/java/io/netty/handler/ssl/OpenSslRenegotiateTest.java
- delete mode 100644 handler/src/test/java/io/netty/handler/ssl/OpenSslServerContextTest.java
- delete mode 100644 handler/src/test/java/io/netty/handler/ssl/OpenSslTestUtils.java
- delete mode 100644 handler/src/test/java/io/netty/handler/ssl/PemEncodedTest.java
- delete mode 100644 handler/src/test/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngineTest.java
- delete mode 100644 handler/src/test/java/io/netty/handler/ssl/SniClientTest.java
- delete mode 100644 handler/src/test/java/io/netty/handler/ssl/SniHandlerTest.java
- delete mode 100644 handler/src/test/java/io/netty/handler/ssl/SslContextBuilderTest.java
- delete mode 100644 handler/src/test/java/io/netty/handler/ssl/SslErrorTest.java
- delete mode 100644 handler/src/test/java/io/netty/handler/ssl/ocsp/OcspTest.java
diff --git a/handler/pom.xml b/handler/pom.xml
-index 7535c45..d0ed1bc 100644
+index be8206dc89..e28cc6f7af 100644
--- a/handler/pom.xml
+++ b/handler/pom.xml
-@@ -50,12 +50,6 @@
+@@ -60,12 +60,6 @@
+ <artifactId>netty-codec</artifactId>
<version>${project.version}</version>
</dependency>
- <dependency>
+- <dependency>
- <groupId>${project.groupId}</groupId>
- <artifactId>${tcnative.artifactId}</artifactId>
- <classifier>${tcnative.classifier}</classifier>
- <optional>true</optional>
- </dependency>
-- <dependency>
+ <dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
- <optional>true</optional>
-diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSsl.java b/handler/src/main/java/io/netty/handler/ssl/OpenSsl.java
+diff --git a/handler/src/main/java/io/netty/handler/ssl/CipherSuiteConverter.java b/handler/src/main/java/io/netty/handler/ssl/CipherSuiteConverter.java
deleted file mode 100644
-index d2f091a..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/OpenSsl.java
+index 94e951f7f5..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/CipherSuiteConverter.java
+++ /dev/null
-@@ -1,503 +0,0 @@
+@@ -1,494 +0,0 @@
-/*
- * Copyright 2014 The Netty Project
- *
@@ -121,499 +107,490 @@ index d2f091a..0000000
-
-package io.netty.handler.ssl;
-
--import io.netty.buffer.ByteBuf;
--import io.netty.handler.ssl.util.SelfSignedCertificate;
--import io.netty.util.ReferenceCountUtil;
--import io.netty.util.ReferenceCounted;
--import io.netty.util.internal.NativeLibraryLoader;
--import io.netty.util.internal.SystemPropertyUtil;
+-import io.netty.util.internal.PlatformDependent;
-import io.netty.util.internal.logging.InternalLogger;
-import io.netty.util.internal.logging.InternalLoggerFactory;
--import io.netty.internal.tcnative.Buffer;
--import io.netty.internal.tcnative.Library;
--import io.netty.internal.tcnative.SSL;
--import io.netty.internal.tcnative.SSLContext;
-
--import java.security.AccessController;
--import java.security.PrivilegedAction;
-import java.util.Collections;
--import java.util.LinkedHashSet;
--import java.util.Locale;
--import java.util.Set;
+-import java.util.HashMap;
+-import java.util.Map;
+-import java.util.concurrent.ConcurrentMap;
+-import java.util.regex.Matcher;
+-import java.util.regex.Pattern;
+-
+-import static java.util.Collections.singletonMap;
-
-/**
-- * Tells if <a href="http://netty.io/wiki/forked-tomcat-native.html">{@code netty-tcnative}</a> and its OpenSSL support
-- * are available.
+- * Converts a Java cipher suite string to an OpenSSL cipher suite string and vice versa.
+- *
+- * @see <a href="http://en.wikipedia.org/wiki/Cipher_suite">Wikipedia page about cipher suite</a>
- */
--public final class OpenSsl {
+-final class CipherSuiteConverter {
-
-- private static final InternalLogger logger = InternalLoggerFactory.getInstance(OpenSsl.class);
-- private static final String LINUX = "linux";
-- private static final String UNKNOWN = "unknown";
-- private static final Throwable UNAVAILABILITY_CAUSE;
+- private static final InternalLogger logger = InternalLoggerFactory.getInstance(CipherSuiteConverter.class);
-
-- static final Set<String> AVAILABLE_CIPHER_SUITES;
-- private static final Set<String> AVAILABLE_OPENSSL_CIPHER_SUITES;
-- private static final Set<String> AVAILABLE_JAVA_CIPHER_SUITES;
-- private static final boolean SUPPORTS_KEYMANAGER_FACTORY;
-- private static final boolean SUPPORTS_HOSTNAME_VALIDATION;
-- private static final boolean USE_KEYMANAGER_FACTORY;
-- private static final boolean SUPPORTS_OCSP;
+- /**
+- * A_B_WITH_C_D, where:
+- *
+- * A - TLS or SSL (protocol)
+- * B - handshake algorithm (key exchange and authentication algorithms to be precise)
+- * C - bulk cipher
+- * D - HMAC algorithm
+- *
+- * This regular expression assumes that:
+- *
+- * 1) A is always TLS or SSL, and
+- * 2) D is always a single word.
+- */
+- private static final Pattern JAVA_CIPHERSUITE_PATTERN =
+- Pattern.compile("^(?:TLS|SSL)_((?:(?!_WITH_).)+)_WITH_(.*)_(.*)$");
+-
+- /**
+- * A-B-C, where:
+- *
+- * A - handshake algorithm (key exchange and authentication algorithms to be precise)
+- * B - bulk cipher
+- * C - HMAC algorithm
+- *
+- * This regular expression assumes that:
+- *
+- * 1) A has some deterministic pattern as shown below, and
+- * 2) C is always a single word
+- */
+- private static final Pattern OPENSSL_CIPHERSUITE_PATTERN =
+- // Be very careful not to break the indentation while editing.
+- Pattern.compile(
+- "^(?:(" + // BEGIN handshake algorithm
+- "(?:(?:EXP-)?" +
+- "(?:" +
+- "(?:DHE|EDH|ECDH|ECDHE|SRP|RSA)-(?:DSS|RSA|ECDSA|PSK)|" +
+- "(?:ADH|AECDH|KRB5|PSK|SRP)" +
+- ')' +
+- ")|" +
+- "EXP" +
+- ")-)?" + // END handshake algorithm
+- "(.*)-(.*)$");
+-
+- private static final Pattern JAVA_AES_CBC_PATTERN = Pattern.compile("^(AES)_([0-9]+)_CBC$");
+- private static final Pattern JAVA_AES_PATTERN = Pattern.compile("^(AES)_([0-9]+)_(.*)$");
+- private static final Pattern OPENSSL_AES_CBC_PATTERN = Pattern.compile("^(AES)([0-9]+)$");
+- private static final Pattern OPENSSL_AES_PATTERN = Pattern.compile("^(AES)([0-9]+)-(.*)$");
-
-- // Protocols
-- static final String PROTOCOL_SSL_V2_HELLO = "SSLv2Hello";
-- static final String PROTOCOL_SSL_V2 = "SSLv2";
-- static final String PROTOCOL_SSL_V3 = "SSLv3";
-- static final String PROTOCOL_TLS_V1 = "TLSv1";
-- static final String PROTOCOL_TLS_V1_1 = "TLSv1.1";
-- static final String PROTOCOL_TLS_V1_2 = "TLSv1.2";
+- /**
+- * Java-to-OpenSSL cipher suite conversion map
+- * Note that the Java cipher suite has the protocol prefix (TLS_, SSL_)
+- */
+- private static final ConcurrentMap<String, String> j2o = PlatformDependent.newConcurrentHashMap();
-
-- static final Set<String> SUPPORTED_PROTOCOLS_SET;
+- /**
+- * OpenSSL-to-Java cipher suite conversion map.
+- * Note that one OpenSSL cipher suite can be converted to more than one Java cipher suites because
+- * a Java cipher suite has the protocol name prefix (TLS_, SSL_)
+- */
+- private static final ConcurrentMap<String, Map<String, String>> o2j = PlatformDependent.newConcurrentHashMap();
+-
+- private static final Map<String, String> j2oTls13;
+- private static final Map<String, Map<String, String>> o2jTls13;
-
- static {
-- Throwable cause = null;
+- Map<String, String> j2oTls13Map = new HashMap<String, String>();
+- j2oTls13Map.put("TLS_AES_128_GCM_SHA256", "AEAD-AES128-GCM-SHA256");
+- j2oTls13Map.put("TLS_AES_256_GCM_SHA384", "AEAD-AES256-GCM-SHA384");
+- j2oTls13Map.put("TLS_CHACHA20_POLY1305_SHA256", "AEAD-CHACHA20-POLY1305-SHA256");
+- j2oTls13 = Collections.unmodifiableMap(j2oTls13Map);
+-
+- Map<String, Map<String, String>> o2jTls13Map = new HashMap<String, Map<String, String>>();
+- o2jTls13Map.put("TLS_AES_128_GCM_SHA256", singletonMap("TLS", "TLS_AES_128_GCM_SHA256"));
+- o2jTls13Map.put("TLS_AES_256_GCM_SHA384", singletonMap("TLS", "TLS_AES_256_GCM_SHA384"));
+- o2jTls13Map.put("TLS_CHACHA20_POLY1305_SHA256", singletonMap("TLS", "TLS_CHACHA20_POLY1305_SHA256"));
+- o2jTls13Map.put("AEAD-AES128-GCM-SHA256", singletonMap("TLS", "TLS_AES_128_GCM_SHA256"));
+- o2jTls13Map.put("AEAD-AES256-GCM-SHA384", singletonMap("TLS", "TLS_AES_256_GCM_SHA384"));
+- o2jTls13Map.put("AEAD-CHACHA20-POLY1305-SHA256", singletonMap("TLS", "TLS_CHACHA20_POLY1305_SHA256"));
+- o2jTls13 = Collections.unmodifiableMap(o2jTls13Map);
+- }
-
-- // Test if netty-tcnative is in the classpath first.
-- try {
-- Class.forName("io.netty.internal.tcnative.SSL", false, OpenSsl.class.getClassLoader());
-- } catch (ClassNotFoundException t) {
-- cause = t;
-- logger.debug(
-- "netty-tcnative not in the classpath; " +
-- OpenSslEngine.class.getSimpleName() + " will be unavailable.");
+- /**
+- * Clears the cache for testing purpose.
+- */
+- static void clearCache() {
+- j2o.clear();
+- o2j.clear();
+- }
+-
+- /**
+- * Tests if the specified key-value pair has been cached in Java-to-OpenSSL cache.
+- */
+- static boolean isJ2OCached(String key, String value) {
+- return value.equals(j2o.get(key));
+- }
+-
+- /**
+- * Tests if the specified key-value pair has been cached in OpenSSL-to-Java cache.
+- */
+- static boolean isO2JCached(String key, String protocol, String value) {
+- Map<String, String> p2j = o2j.get(key);
+- if (p2j == null) {
+- return false;
+- } else {
+- return value.equals(p2j.get(protocol));
- }
+- }
-
-- // If in the classpath, try to load the native library and initialize netty-tcnative.
-- if (cause == null) {
-- try {
-- // The JNI library was not already loaded. Load it now.
-- loadTcNative();
-- } catch (Throwable t) {
-- cause = t;
-- logger.debug(
-- "Failed to load netty-tcnative; " +
-- OpenSslEngine.class.getSimpleName() + " will be unavailable, unless the " +
-- "application has already loaded the symbols by some other means. " +
-- "See http://netty.io/wiki/forked-tomcat-native.html for more information.", t);
-- }
+- /**
+- * Converts the specified Java cipher suite to its corresponding OpenSSL cipher suite name.
+- *
+- * @return {@code null} if the conversion has failed
+- */
+- static String toOpenSsl(String javaCipherSuite, boolean boringSSL) {
+- String converted = j2o.get(javaCipherSuite);
+- if (converted != null) {
+- return converted;
+- }
+- return cacheFromJava(javaCipherSuite, boringSSL);
+- }
-
-- try {
-- initializeTcNative();
--
-- // The library was initialized successfully. If loading the library failed above,
-- // reset the cause now since it appears that the library was loaded by some other
-- // means.
-- cause = null;
-- } catch (Throwable t) {
-- if (cause == null) {
-- cause = t;
-- }
-- logger.debug(
-- "Failed to initialize netty-tcnative; " +
-- OpenSslEngine.class.getSimpleName() + " will be unavailable. " +
-- "See http://netty.io/wiki/forked-tomcat-native.html for more information.", t);
-- }
+- private static String cacheFromJava(String javaCipherSuite, boolean boringSSL) {
+- String converted = j2oTls13.get(javaCipherSuite);
+- if (converted != null) {
+- return boringSSL ? converted : javaCipherSuite;
- }
-
-- UNAVAILABILITY_CAUSE = cause;
+- String openSslCipherSuite = toOpenSslUncached(javaCipherSuite, boringSSL);
+- if (openSslCipherSuite == null) {
+- return null;
+- }
-
-- if (cause == null) {
-- logger.debug("netty-tcnative using native library: {}", SSL.versionString());
+- // Cache the mapping.
+- j2o.putIfAbsent(javaCipherSuite, openSslCipherSuite);
-
-- final Set<String> availableOpenSslCipherSuites = new LinkedHashSet<String>(128);
-- boolean supportsKeyManagerFactory = false;
-- boolean useKeyManagerFactory = false;
-- boolean supportsHostNameValidation = false;
-- try {
-- final long sslCtx = SSLContext.make(SSL.SSL_PROTOCOL_ALL, SSL.SSL_MODE_SERVER);
-- long certBio = 0;
-- SelfSignedCertificate cert = null;
-- try {
-- SSLContext.setCipherSuite(sslCtx, "ALL");
-- final long ssl = SSL.newSSL(sslCtx, true);
-- try {
-- for (String c: SSL.getCiphers(ssl)) {
-- // Filter out bad input.
-- if (c == null || c.isEmpty() || availableOpenSslCipherSuites.contains(c)) {
-- continue;
-- }
-- availableOpenSslCipherSuites.add(c);
-- }
-- try {
-- SSL.setHostNameValidation(ssl, 0, "netty.io");
-- supportsHostNameValidation = true;
-- } catch (Throwable ignore) {
-- logger.debug("Hostname Verification not supported.");
-- }
-- try {
-- cert = new SelfSignedCertificate();
-- certBio = ReferenceCountedOpenSslContext.toBIO(cert.cert());
-- SSL.setCertificateChainBio(ssl, certBio, false);
-- supportsKeyManagerFactory = true;
-- try {
-- useKeyManagerFactory = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
-- @Override
-- public Boolean run() {
-- return SystemPropertyUtil.getBoolean(
-- "io.netty.handler.ssl.openssl.useKeyManagerFactory", true);
-- }
-- });
-- } catch (Throwable ignore) {
-- logger.debug("Failed to get useKeyManagerFactory system property.");
-- }
-- } catch (Throwable ignore) {
-- logger.debug("KeyManagerFactory not supported.");
-- }
-- } finally {
-- SSL.freeSSL(ssl);
-- if (certBio != 0) {
-- SSL.freeBIO(certBio);
-- }
-- if (cert != null) {
-- cert.delete();
-- }
-- }
-- } finally {
-- SSLContext.free(sslCtx);
-- }
-- } catch (Exception e) {
-- logger.warn("Failed to get the list of available OpenSSL cipher suites.", e);
-- }
-- AVAILABLE_OPENSSL_CIPHER_SUITES = Collections.unmodifiableSet(availableOpenSslCipherSuites);
+- // Cache the reverse mapping after stripping the protocol prefix (TLS_ or SSL_)
+- final String javaCipherSuiteSuffix = javaCipherSuite.substring(4);
+- Map<String, String> p2j = new HashMap<String, String>(4);
+- p2j.put("", javaCipherSuiteSuffix);
+- p2j.put("SSL", "SSL_" + javaCipherSuiteSuffix);
+- p2j.put("TLS", "TLS_" + javaCipherSuiteSuffix);
+- o2j.put(openSslCipherSuite, p2j);
-
-- final Set<String> availableJavaCipherSuites = new LinkedHashSet<String>(
-- AVAILABLE_OPENSSL_CIPHER_SUITES.size() * 2);
-- for (String cipher: AVAILABLE_OPENSSL_CIPHER_SUITES) {
-- // Included converted but also openssl cipher name
-- availableJavaCipherSuites.add(CipherSuiteConverter.toJava(cipher, "TLS"));
-- availableJavaCipherSuites.add(CipherSuiteConverter.toJava(cipher, "SSL"));
-- }
-- AVAILABLE_JAVA_CIPHER_SUITES = Collections.unmodifiableSet(availableJavaCipherSuites);
+- logger.debug("Cipher suite mapping: {} => {}", javaCipherSuite, openSslCipherSuite);
-
-- final Set<String> availableCipherSuites = new LinkedHashSet<String>(
-- AVAILABLE_OPENSSL_CIPHER_SUITES.size() + AVAILABLE_JAVA_CIPHER_SUITES.size());
-- availableCipherSuites.addAll(AVAILABLE_OPENSSL_CIPHER_SUITES);
-- availableCipherSuites.addAll(AVAILABLE_JAVA_CIPHER_SUITES);
+- return openSslCipherSuite;
+- }
-
-- AVAILABLE_CIPHER_SUITES = availableCipherSuites;
-- SUPPORTS_KEYMANAGER_FACTORY = supportsKeyManagerFactory;
-- SUPPORTS_HOSTNAME_VALIDATION = supportsHostNameValidation;
-- USE_KEYMANAGER_FACTORY = useKeyManagerFactory;
+- static String toOpenSslUncached(String javaCipherSuite, boolean boringSSL) {
+- String converted = j2oTls13.get(javaCipherSuite);
+- if (converted != null) {
+- return boringSSL ? converted : javaCipherSuite;
+- }
-
-- Set<String> protocols = new LinkedHashSet<String>(6);
-- // Seems like there is no way to explicitly disable SSLv2Hello in openssl so it is always enabled
-- protocols.add(PROTOCOL_SSL_V2_HELLO);
-- if (doesSupportProtocol(SSL.SSL_PROTOCOL_SSLV2)) {
-- protocols.add(PROTOCOL_SSL_V2);
-- }
-- if (doesSupportProtocol(SSL.SSL_PROTOCOL_SSLV3)) {
-- protocols.add(PROTOCOL_SSL_V3);
-- }
-- if (doesSupportProtocol(SSL.SSL_PROTOCOL_TLSV1)) {
-- protocols.add(PROTOCOL_TLS_V1);
-- }
-- if (doesSupportProtocol(SSL.SSL_PROTOCOL_TLSV1_1)) {
-- protocols.add(PROTOCOL_TLS_V1_1);
-- }
-- if (doesSupportProtocol(SSL.SSL_PROTOCOL_TLSV1_2)) {
-- protocols.add(PROTOCOL_TLS_V1_2);
-- }
+- Matcher m = JAVA_CIPHERSUITE_PATTERN.matcher(javaCipherSuite);
+- if (!m.matches()) {
+- return null;
+- }
-
-- SUPPORTED_PROTOCOLS_SET = Collections.unmodifiableSet(protocols);
-- SUPPORTS_OCSP = doesSupportOcsp();
+- String handshakeAlgo = toOpenSslHandshakeAlgo(m.group(1));
+- String bulkCipher = toOpenSslBulkCipher(m.group(2));
+- String hmacAlgo = toOpenSslHmacAlgo(m.group(3));
+- if (handshakeAlgo.isEmpty()) {
+- return bulkCipher + '-' + hmacAlgo;
+- } else if (bulkCipher.contains("CHACHA20")) {
+- return handshakeAlgo + '-' + bulkCipher;
- } else {
-- AVAILABLE_OPENSSL_CIPHER_SUITES = Collections.emptySet();
-- AVAILABLE_JAVA_CIPHER_SUITES = Collections.emptySet();
-- AVAILABLE_CIPHER_SUITES = Collections.emptySet();
-- SUPPORTS_KEYMANAGER_FACTORY = false;
-- SUPPORTS_HOSTNAME_VALIDATION = false;
-- USE_KEYMANAGER_FACTORY = false;
-- SUPPORTED_PROTOCOLS_SET = Collections.emptySet();
-- SUPPORTS_OCSP = false;
+- return handshakeAlgo + '-' + bulkCipher + '-' + hmacAlgo;
- }
- }
-
-- private static boolean doesSupportOcsp() {
-- boolean supportsOcsp = false;
-- if (version() >= 0x10002000L) {
-- long sslCtx = -1;
-- try {
-- sslCtx = SSLContext.make(SSL.SSL_PROTOCOL_TLSV1_2, SSL.SSL_MODE_SERVER);
-- SSLContext.enableOcsp(sslCtx, false);
-- supportsOcsp = true;
-- } catch (Exception ignore) {
-- // ignore
-- } finally {
-- if (sslCtx != -1) {
-- SSLContext.free(sslCtx);
-- }
+- private static String toOpenSslHandshakeAlgo(String handshakeAlgo) {
+- final boolean export = handshakeAlgo.endsWith("_EXPORT");
+- if (export) {
+- handshakeAlgo = handshakeAlgo.substring(0, handshakeAlgo.length() - 7);
+- }
+-
+- if ("RSA".equals(handshakeAlgo)) {
+- handshakeAlgo = "";
+- } else if (handshakeAlgo.endsWith("_anon")) {
+- handshakeAlgo = 'A' + handshakeAlgo.substring(0, handshakeAlgo.length() - 5);
+- }
+-
+- if (export) {
+- if (handshakeAlgo.isEmpty()) {
+- handshakeAlgo = "EXP";
+- } else {
+- handshakeAlgo = "EXP-" + handshakeAlgo;
- }
- }
-- return supportsOcsp;
+-
+- return handshakeAlgo.replace('_', '-');
- }
-- private static boolean doesSupportProtocol(int protocol) {
-- long sslCtx = -1;
-- try {
-- sslCtx = SSLContext.make(protocol, SSL.SSL_MODE_COMBINED);
-- return true;
-- } catch (Exception ignore) {
-- return false;
-- } finally {
-- if (sslCtx != -1) {
-- SSLContext.free(sslCtx);
+-
+- private static String toOpenSslBulkCipher(String bulkCipher) {
+- if (bulkCipher.startsWith("AES_")) {
+- Matcher m = JAVA_AES_CBC_PATTERN.matcher(bulkCipher);
+- if (m.matches()) {
+- return m.replaceFirst("$1$2");
+- }
+-
+- m = JAVA_AES_PATTERN.matcher(bulkCipher);
+- if (m.matches()) {
+- return m.replaceFirst("$1$2-$3");
- }
- }
-- }
-
-- /**
-- * Returns {@code true} if and only if
-- * <a href="http://netty.io/wiki/forked-tomcat-native.html">{@code netty-tcnative}</a> and its OpenSSL support
-- * are available.
-- */
-- public static boolean isAvailable() {
-- return UNAVAILABILITY_CAUSE == null;
-- }
+- if ("3DES_EDE_CBC".equals(bulkCipher)) {
+- return "DES-CBC3";
+- }
-
-- /**
-- * Returns {@code true} if the used version of openssl supports
-- * <a href="https://tools.ietf.org/html/rfc7301">ALPN</a>.
-- */
-- public static boolean isAlpnSupported() {
-- return version() >= 0x10002000L;
-- }
+- if ("RC4_128".equals(bulkCipher) || "RC4_40".equals(bulkCipher)) {
+- return "RC4";
+- }
-
-- /**
-- * Returns {@code true} if the used version of OpenSSL supports OCSP stapling.
-- */
-- public static boolean isOcspSupported() {
-- return SUPPORTS_OCSP;
-- }
+- if ("DES40_CBC".equals(bulkCipher) || "DES_CBC_40".equals(bulkCipher)) {
+- return "DES-CBC";
+- }
-
-- /**
-- * Returns the version of the used available OpenSSL library or {@code -1} if {@link #isAvailable()}
-- * returns {@code false}.
-- */
-- public static int version() {
-- return isAvailable() ? SSL.version() : -1;
+- if ("RC2_CBC_40".equals(bulkCipher)) {
+- return "RC2-CBC";
+- }
+-
+- return bulkCipher.replace('_', '-');
- }
-
-- /**
-- * Returns the version string of the used available OpenSSL library or {@code null} if {@link #isAvailable()}
-- * returns {@code false}.
-- */
-- public static String versionString() {
-- return isAvailable() ? SSL.versionString() : null;
+- private static String toOpenSslHmacAlgo(String hmacAlgo) {
+- // Java and OpenSSL use the same algorithm names for:
+- //
+- // * SHA
+- // * SHA256
+- // * MD5
+- //
+- return hmacAlgo;
- }
-
- /**
-- * Ensure that <a href="http://netty.io/wiki/forked-tomcat-native.html">{@code netty-tcnative}</a> and
-- * its OpenSSL support are available.
-- *
-- * @throws UnsatisfiedLinkError if unavailable
+- * Convert from OpenSSL cipher suite name convention to java cipher suite name convention.
+- * @param openSslCipherSuite An OpenSSL cipher suite name.
+- * @param protocol The cryptographic protocol (i.e. SSL, TLS, ...).
+- * @return The translated cipher suite name according to java conventions. This will not be {@code null}.
- */
-- public static void ensureAvailability() {
-- if (UNAVAILABILITY_CAUSE != null) {
-- throw (Error) new UnsatisfiedLinkError(
-- "failed to load the required native library").initCause(UNAVAILABILITY_CAUSE);
+- static String toJava(String openSslCipherSuite, String protocol) {
+- Map<String, String> p2j = o2j.get(openSslCipherSuite);
+- if (p2j == null) {
+- p2j = cacheFromOpenSsl(openSslCipherSuite);
+- // This may happen if this method is queried when OpenSSL doesn't yet have a cipher setup. It will return
+- // "(NONE)" in this case.
+- if (p2j == null) {
+- return null;
+- }
+- }
+-
+- String javaCipherSuite = p2j.get(protocol);
+- if (javaCipherSuite == null) {
+- String cipher = p2j.get("");
+- if (cipher == null) {
+- return null;
+- }
+- javaCipherSuite = protocol + '_' + cipher;
- }
+-
+- return javaCipherSuite;
- }
-
-- /**
-- * Returns the cause of unavailability of
-- * <a href="http://netty.io/wiki/forked-tomcat-native.html">{@code netty-tcnative}</a> and its OpenSSL support.
-- *
-- * @return the cause if unavailable. {@code null} if available.
-- */
-- public static Throwable unavailabilityCause() {
-- return UNAVAILABILITY_CAUSE;
-- }
--
-- /**
-- * @deprecated use {@link #availableOpenSslCipherSuites()}
-- */
-- @Deprecated
-- public static Set<String> availableCipherSuites() {
-- return availableOpenSslCipherSuites();
-- }
+- private static Map<String, String> cacheFromOpenSsl(String openSslCipherSuite) {
+- Map<String, String> converted = o2jTls13.get(openSslCipherSuite);
+- if (converted != null) {
+- return converted;
+- }
-
-- /**
-- * Returns all the available OpenSSL cipher suites.
-- * Please note that the returned array may include the cipher suites that are insecure or non-functional.
-- */
-- public static Set<String> availableOpenSslCipherSuites() {
-- return AVAILABLE_OPENSSL_CIPHER_SUITES;
-- }
+- String javaCipherSuiteSuffix = toJavaUncached0(openSslCipherSuite, false);
+- if (javaCipherSuiteSuffix == null) {
+- return null;
+- }
-
-- /**
-- * Returns all the available cipher suites (Java-style).
-- * Please note that the returned array may include the cipher suites that are insecure or non-functional.
-- */
-- public static Set<String> availableJavaCipherSuites() {
-- return AVAILABLE_JAVA_CIPHER_SUITES;
-- }
+- final String javaCipherSuiteSsl = "SSL_" + javaCipherSuiteSuffix;
+- final String javaCipherSuiteTls = "TLS_" + javaCipherSuiteSuffix;
-
-- /**
-- * Returns {@code true} if and only if the specified cipher suite is available in OpenSSL.
-- * Both Java-style cipher suite and OpenSSL-style cipher suite are accepted.
-- */
-- public static boolean isCipherSuiteAvailable(String cipherSuite) {
-- String converted = CipherSuiteConverter.toOpenSsl(cipherSuite);
-- if (converted != null) {
-- cipherSuite = converted;
-- }
-- return AVAILABLE_OPENSSL_CIPHER_SUITES.contains(cipherSuite);
-- }
+- // Cache the mapping.
+- final Map<String, String> p2j = new HashMap<String, String>(4);
+- p2j.put("", javaCipherSuiteSuffix);
+- p2j.put("SSL", javaCipherSuiteSsl);
+- p2j.put("TLS", javaCipherSuiteTls);
+- o2j.putIfAbsent(openSslCipherSuite, p2j);
-
-- /**
-- * Returns {@code true} if {@link javax.net.ssl.KeyManagerFactory} is supported when using OpenSSL.
-- */
-- public static boolean supportsKeyManagerFactory() {
-- return SUPPORTS_KEYMANAGER_FACTORY;
-- }
+- // Cache the reverse mapping after adding the protocol prefix (TLS_ or SSL_)
+- j2o.putIfAbsent(javaCipherSuiteTls, openSslCipherSuite);
+- j2o.putIfAbsent(javaCipherSuiteSsl, openSslCipherSuite);
-
-- /**
-- * Returns {@code true} if <a href="https://wiki.openssl.org/index.php/Hostname_validation">Hostname Validation</a>
-- * is supported when using OpenSSL.
-- */
-- public static boolean supportsHostnameValidation() {
-- return SUPPORTS_HOSTNAME_VALIDATION;
-- }
+- logger.debug("Cipher suite mapping: {} => {}", javaCipherSuiteTls, openSslCipherSuite);
+- logger.debug("Cipher suite mapping: {} => {}", javaCipherSuiteSsl, openSslCipherSuite);
-
-- static boolean useKeyManagerFactory() {
-- return USE_KEYMANAGER_FACTORY;
+- return p2j;
- }
-
-- static long memoryAddress(ByteBuf buf) {
-- assert buf.isDirect();
-- return buf.hasMemoryAddress() ? buf.memoryAddress() : Buffer.address(buf.nioBuffer());
+- static String toJavaUncached(String openSslCipherSuite) {
+- return toJavaUncached0(openSslCipherSuite, true);
- }
-
-- private OpenSsl() { }
+- private static String toJavaUncached0(String openSslCipherSuite, boolean checkTls13) {
+- if (checkTls13) {
+- Map<String, String> converted = o2jTls13.get(openSslCipherSuite);
+- if (converted != null) {
+- return converted.get("TLS");
+- }
+- }
-
-- private static void loadTcNative() throws Exception {
-- String os = normalizeOs(SystemPropertyUtil.get("os.name", ""));
-- String arch = normalizeArch(SystemPropertyUtil.get("os.arch", ""));
+- Matcher m = OPENSSL_CIPHERSUITE_PATTERN.matcher(openSslCipherSuite);
+- if (!m.matches()) {
+- return null;
+- }
-
-- Set<String> libNames = new LinkedHashSet<String>(4);
-- // First, try loading the platform-specific library. Platform-specific
-- // libraries will be available if using a tcnative uber jar.
-- libNames.add("netty-tcnative-" + os + '-' + arch);
-- if (LINUX.equalsIgnoreCase(os)) {
-- // Fedora SSL lib so naming (libssl.so.10 vs libssl.so.1.0.0)..
-- libNames.add("netty-tcnative-" + os + '-' + arch + "-fedora");
+- String handshakeAlgo = m.group(1);
+- final boolean export;
+- if (handshakeAlgo == null) {
+- handshakeAlgo = "";
+- export = false;
+- } else if (handshakeAlgo.startsWith("EXP-")) {
+- handshakeAlgo = handshakeAlgo.substring(4);
+- export = true;
+- } else if ("EXP".equals(handshakeAlgo)) {
+- handshakeAlgo = "";
+- export = true;
+- } else {
+- export = false;
- }
-- // finally the default library.
-- libNames.add("netty-tcnative");
-- // in Java 8, statically compiled JNI code is namespaced
-- libNames.add("netty_tcnative");
-
-- NativeLibraryLoader.loadFirstAvailable(SSL.class.getClassLoader(),
-- libNames.toArray(new String[libNames.size()]));
-- }
+- handshakeAlgo = toJavaHandshakeAlgo(handshakeAlgo, export);
+- String bulkCipher = toJavaBulkCipher(m.group(2), export);
+- String hmacAlgo = toJavaHmacAlgo(m.group(3));
-
-- private static boolean initializeTcNative() throws Exception {
-- return Library.initialize();
+- String javaCipherSuite = handshakeAlgo + "_WITH_" + bulkCipher + '_' + hmacAlgo;
+- // For historical reasons the CHACHA20 ciphers do not follow OpenSSL's custom naming convention and omits the
+- // HMAC algorithm portion of the name. There is currently no way to derive this information because it is
+- // omitted from the OpenSSL cipher name, but they currently all use SHA256 for HMAC [1].
+- // [1] https://www.openssl.org/docs/man1.1.0/apps/ciphers.html
+- return bulkCipher.contains("CHACHA20") ? javaCipherSuite + "_SHA256" : javaCipherSuite;
- }
-
-- private static String normalizeOs(String value) {
-- value = normalize(value);
-- if (value.startsWith("aix")) {
-- return "aix";
+- private static String toJavaHandshakeAlgo(String handshakeAlgo, boolean export) {
+- if (handshakeAlgo.isEmpty()) {
+- handshakeAlgo = "RSA";
+- } else if ("ADH".equals(handshakeAlgo)) {
+- handshakeAlgo = "DH_anon";
+- } else if ("AECDH".equals(handshakeAlgo)) {
+- handshakeAlgo = "ECDH_anon";
- }
-- if (value.startsWith("hpux")) {
-- return "hpux";
+-
+- handshakeAlgo = handshakeAlgo.replace('-', '_');
+- if (export) {
+- return handshakeAlgo + "_EXPORT";
+- } else {
+- return handshakeAlgo;
- }
-- if (value.startsWith("os400")) {
-- // Avoid the names such as os4000
-- if (value.length() <= 5 || !Character.isDigit(value.charAt(5))) {
-- return "os400";
+- }
+-
+- private static String toJavaBulkCipher(String bulkCipher, boolean export) {
+- if (bulkCipher.startsWith("AES")) {
+- Matcher m = OPENSSL_AES_CBC_PATTERN.matcher(bulkCipher);
+- if (m.matches()) {
+- return m.replaceFirst("$1_$2_CBC");
+- }
+-
+- m = OPENSSL_AES_PATTERN.matcher(bulkCipher);
+- if (m.matches()) {
+- return m.replaceFirst("$1_$2_$3");
- }
- }
-- if (value.startsWith(LINUX)) {
-- return LINUX;
-- }
-- if (value.startsWith("macosx") || value.startsWith("osx")) {
-- return "osx";
-- }
-- if (value.startsWith("freebsd")) {
-- return "freebsd";
-- }
-- if (value.startsWith("openbsd")) {
-- return "openbsd";
+-
+- if ("DES-CBC3".equals(bulkCipher)) {
+- return "3DES_EDE_CBC";
- }
-- if (value.startsWith("netbsd")) {
-- return "netbsd";
+-
+- if ("RC4".equals(bulkCipher)) {
+- if (export) {
+- return "RC4_40";
+- } else {
+- return "RC4_128";
+- }
- }
-- if (value.startsWith("solaris") || value.startsWith("sunos")) {
-- return "sunos";
+-
+- if ("DES-CBC".equals(bulkCipher)) {
+- if (export) {
+- return "DES_CBC_40";
+- } else {
+- return "DES_CBC";
+- }
- }
-- if (value.startsWith("windows")) {
-- return "windows";
+-
+- if ("RC2-CBC".equals(bulkCipher)) {
+- if (export) {
+- return "RC2_CBC_40";
+- } else {
+- return "RC2_CBC";
+- }
- }
-
-- return UNKNOWN;
+- return bulkCipher.replace('-', '_');
- }
-
-- private static String normalizeArch(String value) {
-- value = normalize(value);
-- if (value.matches("^(x8664|amd64|ia32e|em64t|x64)$")) {
-- return "x86_64";
-- }
-- if (value.matches("^(x8632|x86|i[3-6]86|ia32|x32)$")) {
-- return "x86_32";
-- }
-- if (value.matches("^(ia64|itanium64)$")) {
-- return "itanium_64";
-- }
-- if (value.matches("^(sparc|sparc32)$")) {
-- return "sparc_32";
-- }
-- if (value.matches("^(sparcv9|sparc64)$")) {
-- return "sparc_64";
-- }
-- if (value.matches("^(arm|arm32)$")) {
-- return "arm_32";
-- }
-- if ("aarch64".equals(value)) {
-- return "aarch_64";
-- }
-- if (value.matches("^(ppc|ppc32)$")) {
-- return "ppc_32";
-- }
-- if ("ppc64".equals(value)) {
-- return "ppc_64";
+- private static String toJavaHmacAlgo(String hmacAlgo) {
+- // Java and OpenSSL use the same algorithm names for:
+- //
+- // * SHA
+- // * SHA256
+- // * MD5
+- //
+- return hmacAlgo;
+- }
+-
+- /**
+- * Convert the given ciphers if needed to OpenSSL format and append them to the correct {@link StringBuilder}
+- * depending on if its a TLSv1.3 cipher or not. If this methods returns without throwing an exception its
+- * guaranteed that at least one of the {@link StringBuilder}s contain some ciphers that can be used to configure
+- * OpenSSL.
+- */
+- static void convertToCipherStrings(Iterable<String> cipherSuites, StringBuilder cipherBuilder,
+- StringBuilder cipherTLSv13Builder, boolean boringSSL) {
+- for (String c: cipherSuites) {
+- if (c == null) {
+- break;
+- }
+-
+- String converted = toOpenSsl(c, boringSSL);
+- if (converted == null) {
+- converted = c;
+- }
+-
+- if (!OpenSsl.isCipherSuiteAvailable(converted)) {
+- throw new IllegalArgumentException("unsupported cipher suite: " + c + '(' + converted + ')');
+- }
+-
+- if (SslUtils.isTLSv13Cipher(converted) || SslUtils.isTLSv13Cipher(c)) {
+- cipherTLSv13Builder.append(converted);
+- cipherTLSv13Builder.append(':');
+- } else {
+- cipherBuilder.append(converted);
+- cipherBuilder.append(':');
+- }
- }
-- if ("ppc64le".equals(value)) {
-- return "ppcle_64";
+-
+- if (cipherBuilder.length() == 0 && cipherTLSv13Builder.length() == 0) {
+- throw new IllegalArgumentException("empty cipher suites");
- }
-- if ("s390".equals(value)) {
-- return "s390_32";
+- if (cipherBuilder.length() > 0) {
+- cipherBuilder.setLength(cipherBuilder.length() - 1);
- }
-- if ("s390x".equals(value)) {
-- return "s390_64";
+- if (cipherTLSv13Builder.length() > 0) {
+- cipherTLSv13Builder.setLength(cipherTLSv13Builder.length() - 1);
- }
--
-- return UNKNOWN;
- }
-
-- private static String normalize(String value) {
-- return value.toLowerCase(Locale.US).replaceAll("[^a-z0-9]+", "");
-- }
--
-- static void releaseIfNeeded(ReferenceCounted counted) {
-- if (counted.refCnt() > 0) {
-- ReferenceCountUtil.safeRelease(counted);
-- }
-- }
+- private CipherSuiteConverter() { }
-}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslCertificateException.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslCertificateException.java
+diff --git a/handler/src/main/java/io/netty/handler/ssl/DefaultOpenSslKeyMaterial.java b/handler/src/main/java/io/netty/handler/ssl/DefaultOpenSslKeyMaterial.java
deleted file mode 100644
-index 4672d00..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/OpenSslCertificateException.java
+index fcea5266f2..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/DefaultOpenSslKeyMaterial.java
+++ /dev/null
-@@ -1,79 +0,0 @@
+@@ -1,126 +0,0 @@
-/*
-- * Copyright 2016 The Netty Project
+- * Copyright 2018 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
@@ -629,74 +606,121 @@ index 4672d00..0000000
- */
-package io.netty.handler.ssl;
-
--import io.netty.internal.tcnative.CertificateVerifier;
+-import io.netty.internal.tcnative.SSL;
+-import io.netty.util.AbstractReferenceCounted;
+-import io.netty.util.IllegalReferenceCountException;
+-import io.netty.util.ResourceLeakDetector;
+-import io.netty.util.ResourceLeakDetectorFactory;
+-import io.netty.util.ResourceLeakTracker;
-
--import java.security.cert.CertificateException;
+-import java.security.cert.X509Certificate;
-
--/**
-- * A special {@link CertificateException} which allows to specify which error code is included in the
-- * SSL Record. This only work when {@link SslProvider#OPENSSL} or {@link SslProvider#OPENSSL_REFCNT} is used.
-- */
--public final class OpenSslCertificateException extends CertificateException {
-- private static final long serialVersionUID = 5542675253797129798L;
+-final class DefaultOpenSslKeyMaterial extends AbstractReferenceCounted implements OpenSslKeyMaterial {
-
-- private final int errorCode;
+- private static final ResourceLeakDetector<DefaultOpenSslKeyMaterial> leakDetector =
+- ResourceLeakDetectorFactory.instance().newResourceLeakDetector(DefaultOpenSslKeyMaterial.class);
+- private final ResourceLeakTracker<DefaultOpenSslKeyMaterial> leak;
+- private final X509Certificate[] x509CertificateChain;
+- private long chain;
+- private long privateKey;
-
-- /**
-- * Construct a new exception with the
-- * <a href="https://www.openssl.org/docs/manmaster/apps/verify.html">error code</a>.
-- */
-- public OpenSslCertificateException(int errorCode) {
-- this((String) null, errorCode);
+- DefaultOpenSslKeyMaterial(long chain, long privateKey, X509Certificate[] x509CertificateChain) {
+- this.chain = chain;
+- this.privateKey = privateKey;
+- this.x509CertificateChain = x509CertificateChain;
+- leak = leakDetector.track(this);
- }
-
-- /**
-- * Construct a new exception with the msg and
-- * <a href="https://www.openssl.org/docs/manmaster/apps/verify.html">error code</a> .
-- */
-- public OpenSslCertificateException(String msg, int errorCode) {
-- super(msg);
-- this.errorCode = checkErrorCode(errorCode);
+- @Override
+- public X509Certificate[] certificateChain() {
+- return x509CertificateChain.clone();
- }
-
-- /**
-- * Construct a new exception with the msg, cause and
-- * <a href="https://www.openssl.org/docs/manmaster/apps/verify.html">error code</a> .
-- */
-- public OpenSslCertificateException(String message, Throwable cause, int errorCode) {
-- super(message, cause);
-- this.errorCode = checkErrorCode(errorCode);
+- @Override
+- public long certificateChainAddress() {
+- if (refCnt() <= 0) {
+- throw new IllegalReferenceCountException();
+- }
+- return chain;
- }
-
-- /**
-- * Construct a new exception with the cause and
-- * <a href="https://www.openssl.org/docs/manmaster/apps/verify.html">error code</a> .
-- */
-- public OpenSslCertificateException(Throwable cause, int errorCode) {
-- this(null, cause, errorCode);
+- @Override
+- public long privateKeyAddress() {
+- if (refCnt() <= 0) {
+- throw new IllegalReferenceCountException();
+- }
+- return privateKey;
- }
-
-- /**
-- * Return the <a href="https://www.openssl.org/docs/man1.0.2/apps/verify.html">error code</a> to use.
-- */
-- public int errorCode() {
-- return errorCode;
+- @Override
+- protected void deallocate() {
+- SSL.freeX509Chain(chain);
+- chain = 0;
+- SSL.freePrivateKey(privateKey);
+- privateKey = 0;
+- if (leak != null) {
+- boolean closed = leak.close(this);
+- assert closed;
+- }
- }
-
-- private static int checkErrorCode(int errorCode) {
-- if (!CertificateVerifier.isValid(errorCode)) {
-- throw new IllegalArgumentException("errorCode '" + errorCode +
-- "' invalid, see https://www.openssl.org/docs/man1.0.2/apps/verify.html.");
+- @Override
+- public DefaultOpenSslKeyMaterial retain() {
+- if (leak != null) {
+- leak.record();
- }
-- return errorCode;
+- super.retain();
+- return this;
+- }
+-
+- @Override
+- public DefaultOpenSslKeyMaterial retain(int increment) {
+- if (leak != null) {
+- leak.record();
+- }
+- super.retain(increment);
+- return this;
+- }
+-
+- @Override
+- public DefaultOpenSslKeyMaterial touch() {
+- if (leak != null) {
+- leak.record();
+- }
+- super.touch();
+- return this;
+- }
+-
+- @Override
+- public DefaultOpenSslKeyMaterial touch(Object hint) {
+- if (leak != null) {
+- leak.record(hint);
+- }
+- return this;
+- }
+-
+- @Override
+- public boolean release() {
+- if (leak != null) {
+- leak.record();
+- }
+- return super.release();
+- }
+-
+- @Override
+- public boolean release(int decrement) {
+- if (leak != null) {
+- leak.record();
+- }
+- return super.release(decrement);
- }
-}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslClientContext.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslClientContext.java
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSsl.java b/handler/src/main/java/io/netty/handler/ssl/OpenSsl.java
deleted file mode 100644
-index 46412e9..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/OpenSslClientContext.java
+index d7d44cf3e7..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSsl.java
+++ /dev/null
-@@ -1,211 +0,0 @@
+@@ -1,610 +0,0 @@
-/*
- * Copyright 2014 The Netty Project
- *
@@ -712,210 +736,609 @@ index 46412e9..0000000
- * License for the specific language governing permissions and limitations
- * under the License.
- */
+-
-package io.netty.handler.ssl;
-
+-import io.netty.buffer.ByteBuf;
+-import io.netty.buffer.ByteBufAllocator;
+-import io.netty.buffer.UnpooledByteBufAllocator;
+-import io.netty.internal.tcnative.Buffer;
+-import io.netty.internal.tcnative.Library;
-import io.netty.internal.tcnative.SSL;
+-import io.netty.internal.tcnative.SSLContext;
+-import io.netty.util.CharsetUtil;
+-import io.netty.util.ReferenceCountUtil;
+-import io.netty.util.ReferenceCounted;
+-import io.netty.util.internal.EmptyArrays;
+-import io.netty.util.internal.NativeLibraryLoader;
+-import io.netty.util.internal.PlatformDependent;
+-import io.netty.util.internal.SystemPropertyUtil;
+-import io.netty.util.internal.logging.InternalLogger;
+-import io.netty.util.internal.logging.InternalLoggerFactory;
-
--import java.io.File;
--import java.security.PrivateKey;
+-import java.io.ByteArrayInputStream;
+-import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
+-import java.util.ArrayList;
+-import java.util.Collections;
+-import java.util.LinkedHashSet;
+-import java.util.List;
+-import java.util.Set;
-
--import javax.net.ssl.KeyManagerFactory;
--import javax.net.ssl.SSLException;
--import javax.net.ssl.TrustManager;
--import javax.net.ssl.TrustManagerFactory;
--
--import static io.netty.handler.ssl.ReferenceCountedOpenSslClientContext.newSessionContext;
+-import static io.netty.handler.ssl.SslUtils.*;
-
-/**
-- * A client-side {@link SslContext} which uses OpenSSL's SSL/TLS implementation.
-- * <p>This class will use a finalizer to ensure native resources are automatically cleaned up. To avoid finalizers
-- * and manually release the native memory see {@link ReferenceCountedOpenSslClientContext}.
+- * Tells if <a href="https://netty.io/wiki/forked-tomcat-native.html">{@code netty-tcnative}</a> and its OpenSSL support
+- * are available.
- */
--public final class OpenSslClientContext extends OpenSslContext {
-- private final OpenSslSessionContext sessionContext;
+-public final class OpenSsl {
-
-- /**
-- * Creates a new instance.
-- * @deprecated use {@link SslContextBuilder}
-- */
-- @Deprecated
-- public OpenSslClientContext() throws SSLException {
-- this((File) null, null, null, null, null, null, null, IdentityCipherSuiteFilter.INSTANCE, null, 0, 0);
+- private static final InternalLogger logger = InternalLoggerFactory.getInstance(OpenSsl.class);
+- private static final Throwable UNAVAILABILITY_CAUSE;
+-
+- static final List<String> DEFAULT_CIPHERS;
+- static final Set<String> AVAILABLE_CIPHER_SUITES;
+- private static final Set<String> AVAILABLE_OPENSSL_CIPHER_SUITES;
+- private static final Set<String> AVAILABLE_JAVA_CIPHER_SUITES;
+- private static final boolean SUPPORTS_KEYMANAGER_FACTORY;
+- private static final boolean USE_KEYMANAGER_FACTORY;
+- private static final boolean SUPPORTS_OCSP;
+- private static final boolean TLSV13_SUPPORTED;
+- private static final boolean IS_BORINGSSL;
+- static final Set<String> SUPPORTED_PROTOCOLS_SET;
+- static final String[] EXTRA_SUPPORTED_TLS_1_3_CIPHERS;
+-
+- // self-signed certificate for netty.io and the matching private-key
+- private static final String CERT = "-----BEGIN CERTIFICATE-----\n" +
+- "MIICrjCCAZagAwIBAgIIdSvQPv1QAZQwDQYJKoZIhvcNAQELBQAwFjEUMBIGA1UEAxMLZXhhbXBs\n" +
+- "ZS5jb20wIBcNMTgwNDA2MjIwNjU5WhgPOTk5OTEyMzEyMzU5NTlaMBYxFDASBgNVBAMTC2V4YW1w\n" +
+- "bGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAggbWsmDQ6zNzRZ5AW8E3eoGl\n" +
+- "qWvOBDb5Fs1oBRrVQHuYmVAoaqwDzXYJ0LOwa293AgWEQ1jpcbZ2hpoYQzqEZBTLnFhMrhRFlH6K\n" +
+- "bJND8Y33kZ/iSVBBDuGbdSbJShlM+4WwQ9IAso4MZ4vW3S1iv5fGGpLgbtXRmBf/RU8omN0Gijlv\n" +
+- "WlLWHWijLN8xQtySFuBQ7ssW8RcKAary3pUm6UUQB+Co6lnfti0Tzag8PgjhAJq2Z3wbsGRnP2YS\n" +
+- "vYoaK6qzmHXRYlp/PxrjBAZAmkLJs4YTm/XFF+fkeYx4i9zqHbyone5yerRibsHaXZWLnUL+rFoe\n" +
+- "MdKvr0VS3sGmhQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQADQi441pKmXf9FvUV5EHU4v8nJT9Iq\n" +
+- "yqwsKwXnr7AsUlDGHBD7jGrjAXnG5rGxuNKBQ35wRxJATKrUtyaquFUL6H8O6aGQehiFTk6zmPbe\n" +
+- "12Gu44vqqTgIUxnv3JQJiox8S2hMxsSddpeCmSdvmalvD6WG4NthH6B9ZaBEiep1+0s0RUaBYn73\n" +
+- "I7CCUaAtbjfR6pcJjrFk5ei7uwdQZFSJtkP2z8r7zfeANJddAKFlkaMWn7u+OIVuB4XPooWicObk\n" +
+- "NAHFtP65bocUYnDpTVdiyvn8DdqyZ/EO8n1bBKBzuSLplk2msW4pdgaFgY7Vw/0wzcFXfUXmL1uy\n" +
+- "G8sQD/wx\n" +
+- "-----END CERTIFICATE-----";
+-
+- private static final String KEY = "-----BEGIN PRIVATE KEY-----\n" +
+- "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCCBtayYNDrM3NFnkBbwTd6gaWp\n" +
+- "a84ENvkWzWgFGtVAe5iZUChqrAPNdgnQs7Brb3cCBYRDWOlxtnaGmhhDOoRkFMucWEyuFEWUfops\n" +
+- "k0PxjfeRn+JJUEEO4Zt1JslKGUz7hbBD0gCyjgxni9bdLWK/l8YakuBu1dGYF/9FTyiY3QaKOW9a\n" +
+- "UtYdaKMs3zFC3JIW4FDuyxbxFwoBqvLelSbpRRAH4KjqWd+2LRPNqDw+COEAmrZnfBuwZGc/ZhK9\n" +
+- "ihorqrOYddFiWn8/GuMEBkCaQsmzhhOb9cUX5+R5jHiL3OodvKid7nJ6tGJuwdpdlYudQv6sWh4x\n" +
+- "0q+vRVLewaaFAgMBAAECggEAP8tPJvFtTxhNJAkCloHz0D0vpDHqQBMgntlkgayqmBqLwhyb18pR\n" +
+- "i0qwgh7HHc7wWqOOQuSqlEnrWRrdcI6TSe8R/sErzfTQNoznKWIPYcI/hskk4sdnQ//Yn9/Jvnsv\n" +
+- "U/BBjOTJxtD+sQbhAl80JcA3R+5sArURQkfzzHOL/YMqzAsn5hTzp7HZCxUqBk3KaHRxV7NefeOE\n" +
+- "xlZuWSmxYWfbFIs4kx19/1t7h8CHQWezw+G60G2VBtSBBxDnhBWvqG6R/wpzJ3nEhPLLY9T+XIHe\n" +
+- "ipzdMOOOUZorfIg7M+pyYPji+ZIZxIpY5OjrOzXHciAjRtr5Y7l99K1CG1LguQKBgQDrQfIMxxtZ\n" +
+- "vxU/1cRmUV9l7pt5bjV5R6byXq178LxPKVYNjdZ840Q0/OpZEVqaT1xKVi35ohP1QfNjxPLlHD+K\n" +
+- "iDAR9z6zkwjIrbwPCnb5kuXy4lpwPcmmmkva25fI7qlpHtbcuQdoBdCfr/KkKaUCMPyY89LCXgEw\n" +
+- "5KTDj64UywKBgQCNfbO+eZLGzhiHhtNJurresCsIGWlInv322gL8CSfBMYl6eNfUTZvUDdFhPISL\n" +
+- "UljKWzXDrjw0ujFSPR0XhUGtiq89H+HUTuPPYv25gVXO+HTgBFZEPl4PpA+BUsSVZy0NddneyqLk\n" +
+- "42Wey9omY9Q8WsdNQS5cbUvy0uG6WFoX7wKBgQDZ1jpW8pa0x2bZsQsm4vo+3G5CRnZlUp+XlWt2\n" +
+- "dDcp5dC0xD1zbs1dc0NcLeGDOTDv9FSl7hok42iHXXq8AygjEm/QcuwwQ1nC2HxmQP5holAiUs4D\n" +
+- "WHM8PWs3wFYPzE459EBoKTxeaeP/uWAn+he8q7d5uWvSZlEcANs/6e77eQKBgD21Ar0hfFfj7mK8\n" +
+- "9E0FeRZBsqK3omkfnhcYgZC11Xa2SgT1yvs2Va2n0RcdM5kncr3eBZav2GYOhhAdwyBM55XuE/sO\n" +
+- "eokDVutNeuZ6d5fqV96TRaRBpvgfTvvRwxZ9hvKF4Vz+9wfn/JvCwANaKmegF6ejs7pvmF3whq2k\n" +
+- "drZVAoGAX5YxQ5XMTD0QbMAl7/6qp6S58xNoVdfCkmkj1ZLKaHKIjS/benkKGlySVQVPexPfnkZx\n" +
+- "p/Vv9yyphBoudiTBS9Uog66ueLYZqpgxlM/6OhYg86Gm3U2ycvMxYjBM1NFiyze21AqAhI+HX+Ot\n" +
+- "mraV2/guSgDgZAhukRZzeQ2RucI=\n" +
+- "-----END PRIVATE KEY-----";
+-
+- static {
+- Throwable cause = null;
+-
+- if (SystemPropertyUtil.getBoolean("io.netty.handler.ssl.noOpenSsl", false)) {
+- cause = new UnsupportedOperationException(
+- "OpenSSL was explicit disabled with -Dio.netty.handler.ssl.noOpenSsl=true");
+-
+- logger.debug(
+- "netty-tcnative explicit disabled; " +
+- OpenSslEngine.class.getSimpleName() + " will be unavailable.", cause);
+- } else {
+- // Test if netty-tcnative is in the classpath first.
+- try {
+- Class.forName("io.netty.internal.tcnative.SSLContext", false, OpenSsl.class.getClassLoader());
+- } catch (ClassNotFoundException t) {
+- cause = t;
+- logger.debug(
+- "netty-tcnative not in the classpath; " +
+- OpenSslEngine.class.getSimpleName() + " will be unavailable.");
+- }
+-
+- // If in the classpath, try to load the native library and initialize netty-tcnative.
+- if (cause == null) {
+- try {
+- // The JNI library was not already loaded. Load it now.
+- loadTcNative();
+- } catch (Throwable t) {
+- cause = t;
+- logger.debug(
+- "Failed to load netty-tcnative; " +
+- OpenSslEngine.class.getSimpleName() + " will be unavailable, unless the " +
+- "application has already loaded the symbols by some other means. " +
+- "See https://netty.io/wiki/forked-tomcat-native.html for more information.", t);
+- }
+-
+- try {
+- String engine = SystemPropertyUtil.get("io.netty.handler.ssl.openssl.engine", null);
+- if (engine == null) {
+- logger.debug("Initialize netty-tcnative using engine: 'default'");
+- } else {
+- logger.debug("Initialize netty-tcnative using engine: '{}'", engine);
+- }
+- initializeTcNative(engine);
+-
+- // The library was initialized successfully. If loading the library failed above,
+- // reset the cause now since it appears that the library was loaded by some other
+- // means.
+- cause = null;
+- } catch (Throwable t) {
+- if (cause == null) {
+- cause = t;
+- }
+- logger.debug(
+- "Failed to initialize netty-tcnative; " +
+- OpenSslEngine.class.getSimpleName() + " will be unavailable. " +
+- "See https://netty.io/wiki/forked-tomcat-native.html for more information.", t);
+- }
+- }
+- }
+-
+- UNAVAILABILITY_CAUSE = cause;
+-
+- if (cause == null) {
+- logger.debug("netty-tcnative using native library: {}", SSL.versionString());
+-
+- final List<String> defaultCiphers = new ArrayList<String>();
+- final Set<String> availableOpenSslCipherSuites = new LinkedHashSet<String>(128);
+- boolean supportsKeyManagerFactory = false;
+- boolean useKeyManagerFactory = false;
+- boolean tlsv13Supported = false;
+-
+- IS_BORINGSSL = "BoringSSL".equals(versionString());
+- if (IS_BORINGSSL) {
+- EXTRA_SUPPORTED_TLS_1_3_CIPHERS = new String [] { "TLS_AES_128_GCM_SHA256",
+- "TLS_AES_256_GCM_SHA384" ,
+- "TLS_CHACHA20_POLY1305_SHA256" };
+- } else {
+- EXTRA_SUPPORTED_TLS_1_3_CIPHERS = EmptyArrays.EMPTY_STRINGS;
+- }
+-
+- try {
+- final long sslCtx = SSLContext.make(SSL.SSL_PROTOCOL_ALL, SSL.SSL_MODE_SERVER);
+- long certBio = 0;
+- long keyBio = 0;
+- long cert = 0;
+- long key = 0;
+- try {
+- try {
+- StringBuilder tlsv13Ciphers = new StringBuilder();
+-
+- for (String cipher: TLSV13_CIPHERS) {
+- String converted = CipherSuiteConverter.toOpenSsl(cipher, IS_BORINGSSL);
+- if (converted != null) {
+- tlsv13Ciphers.append(converted).append(':');
+- }
+- }
+- if (tlsv13Ciphers.length() == 0) {
+- tlsv13Supported = false;
+- } else {
+- tlsv13Ciphers.setLength(tlsv13Ciphers.length() - 1);
+- SSLContext.setCipherSuite(sslCtx, tlsv13Ciphers.toString() , true);
+- tlsv13Supported = true;
+- }
+-
+- } catch (Exception ignore) {
+- tlsv13Supported = false;
+- }
+-
+- SSLContext.setCipherSuite(sslCtx, "ALL", false);
+-
+- final long ssl = SSL.newSSL(sslCtx, true);
+- try {
+- for (String c: SSL.getCiphers(ssl)) {
+- // Filter out bad input.
+- if (c == null || c.isEmpty() || availableOpenSslCipherSuites.contains(c) ||
+- // Filter out TLSv1.3 ciphers if not supported.
+- !tlsv13Supported && isTLSv13Cipher(c)) {
+- continue;
+- }
+- availableOpenSslCipherSuites.add(c);
+- }
+- if (IS_BORINGSSL) {
+- // Currently BoringSSL does not include these when calling SSL.getCiphers() even when these
+- // are supported.
+- Collections.addAll(availableOpenSslCipherSuites, EXTRA_SUPPORTED_TLS_1_3_CIPHERS);
+- Collections.addAll(availableOpenSslCipherSuites,
+- "AEAD-AES128-GCM-SHA256",
+- "AEAD-AES256-GCM-SHA384",
+- "AEAD-CHACHA20-POLY1305-SHA256");
+- }
+-
+- PemEncoded privateKey = PemPrivateKey.valueOf(KEY.getBytes(CharsetUtil.US_ASCII));
+- try {
+- // Let's check if we can set a callback, which may not work if the used OpenSSL version
+- // is to old.
+- SSLContext.setCertificateCallback(sslCtx, null);
+-
+- X509Certificate certificate = selfSignedCertificate();
+- certBio = ReferenceCountedOpenSslContext.toBIO(ByteBufAllocator.DEFAULT, certificate);
+- cert = SSL.parseX509Chain(certBio);
+-
+- keyBio = ReferenceCountedOpenSslContext.toBIO(
+- UnpooledByteBufAllocator.DEFAULT, privateKey.retain());
+- key = SSL.parsePrivateKey(keyBio, null);
+-
+- SSL.setKeyMaterial(ssl, cert, key);
+- supportsKeyManagerFactory = true;
+- try {
+- boolean propertySet = SystemPropertyUtil.contains(
+- "io.netty.handler.ssl.openssl.useKeyManagerFactory");
+- if (!IS_BORINGSSL) {
+- useKeyManagerFactory = SystemPropertyUtil.getBoolean(
+- "io.netty.handler.ssl.openssl.useKeyManagerFactory", true);
+-
+- if (propertySet) {
+- logger.info("System property " +
+- "'io.netty.handler.ssl.openssl.useKeyManagerFactory'" +
+- " is deprecated and so will be ignored in the future");
+- }
+- } else {
+- useKeyManagerFactory = true;
+- if (propertySet) {
+- logger.info("System property " +
+- "'io.netty.handler.ssl.openssl.useKeyManagerFactory'" +
+- " is deprecated and will be ignored when using BoringSSL");
+- }
+- }
+- } catch (Throwable ignore) {
+- logger.debug("Failed to get useKeyManagerFactory system property.");
+- }
+- } catch (Error ignore) {
+- logger.debug("KeyManagerFactory not supported.");
+- } finally {
+- privateKey.release();
+- }
+- } finally {
+- SSL.freeSSL(ssl);
+- if (certBio != 0) {
+- SSL.freeBIO(certBio);
+- }
+- if (keyBio != 0) {
+- SSL.freeBIO(keyBio);
+- }
+- if (cert != 0) {
+- SSL.freeX509Chain(cert);
+- }
+- if (key != 0) {
+- SSL.freePrivateKey(key);
+- }
+- }
+- } finally {
+- SSLContext.free(sslCtx);
+- }
+- } catch (Exception e) {
+- logger.warn("Failed to get the list of available OpenSSL cipher suites.", e);
+- }
+- AVAILABLE_OPENSSL_CIPHER_SUITES = Collections.unmodifiableSet(availableOpenSslCipherSuites);
+- final Set<String> availableJavaCipherSuites = new LinkedHashSet<String>(
+- AVAILABLE_OPENSSL_CIPHER_SUITES.size() * 2);
+- for (String cipher: AVAILABLE_OPENSSL_CIPHER_SUITES) {
+- // Included converted but also openssl cipher name
+- if (!isTLSv13Cipher(cipher)) {
+- availableJavaCipherSuites.add(CipherSuiteConverter.toJava(cipher, "TLS"));
+- availableJavaCipherSuites.add(CipherSuiteConverter.toJava(cipher, "SSL"));
+- } else {
+- // TLSv1.3 ciphers have the correct format.
+- availableJavaCipherSuites.add(cipher);
+- }
+- }
+-
+- addIfSupported(availableJavaCipherSuites, defaultCiphers, DEFAULT_CIPHER_SUITES);
+- addIfSupported(availableJavaCipherSuites, defaultCiphers, TLSV13_CIPHER_SUITES);
+-
+- useFallbackCiphersIfDefaultIsEmpty(defaultCiphers, availableJavaCipherSuites);
+- DEFAULT_CIPHERS = Collections.unmodifiableList(defaultCiphers);
+-
+- AVAILABLE_JAVA_CIPHER_SUITES = Collections.unmodifiableSet(availableJavaCipherSuites);
+-
+- final Set<String> availableCipherSuites = new LinkedHashSet<String>(
+- AVAILABLE_OPENSSL_CIPHER_SUITES.size() + AVAILABLE_JAVA_CIPHER_SUITES.size());
+- availableCipherSuites.addAll(AVAILABLE_OPENSSL_CIPHER_SUITES);
+- availableCipherSuites.addAll(AVAILABLE_JAVA_CIPHER_SUITES);
+-
+- AVAILABLE_CIPHER_SUITES = availableCipherSuites;
+- SUPPORTS_KEYMANAGER_FACTORY = supportsKeyManagerFactory;
+- USE_KEYMANAGER_FACTORY = useKeyManagerFactory;
+-
+- Set<String> protocols = new LinkedHashSet<String>(6);
+- // Seems like there is no way to explicitly disable SSLv2Hello in openssl so it is always enabled
+- protocols.add(PROTOCOL_SSL_V2_HELLO);
+- if (doesSupportProtocol(SSL.SSL_PROTOCOL_SSLV2, SSL.SSL_OP_NO_SSLv2)) {
+- protocols.add(PROTOCOL_SSL_V2);
+- }
+- if (doesSupportProtocol(SSL.SSL_PROTOCOL_SSLV3, SSL.SSL_OP_NO_SSLv3)) {
+- protocols.add(PROTOCOL_SSL_V3);
+- }
+- if (doesSupportProtocol(SSL.SSL_PROTOCOL_TLSV1, SSL.SSL_OP_NO_TLSv1)) {
+- protocols.add(PROTOCOL_TLS_V1);
+- }
+- if (doesSupportProtocol(SSL.SSL_PROTOCOL_TLSV1_1, SSL.SSL_OP_NO_TLSv1_1)) {
+- protocols.add(PROTOCOL_TLS_V1_1);
+- }
+- if (doesSupportProtocol(SSL.SSL_PROTOCOL_TLSV1_2, SSL.SSL_OP_NO_TLSv1_2)) {
+- protocols.add(PROTOCOL_TLS_V1_2);
+- }
+-
+- // This is only supported by java11 and later.
+- if (tlsv13Supported && doesSupportProtocol(SSL.SSL_PROTOCOL_TLSV1_3, SSL.SSL_OP_NO_TLSv1_3)) {
+- protocols.add(PROTOCOL_TLS_V1_3);
+- TLSV13_SUPPORTED = true;
+- } else {
+- TLSV13_SUPPORTED = false;
+- }
+-
+- SUPPORTED_PROTOCOLS_SET = Collections.unmodifiableSet(protocols);
+- SUPPORTS_OCSP = doesSupportOcsp();
+-
+- if (logger.isDebugEnabled()) {
+- logger.debug("Supported protocols (OpenSSL): {} ", SUPPORTED_PROTOCOLS_SET);
+- logger.debug("Default cipher suites (OpenSSL): {}", DEFAULT_CIPHERS);
+- }
+- } else {
+- DEFAULT_CIPHERS = Collections.emptyList();
+- AVAILABLE_OPENSSL_CIPHER_SUITES = Collections.emptySet();
+- AVAILABLE_JAVA_CIPHER_SUITES = Collections.emptySet();
+- AVAILABLE_CIPHER_SUITES = Collections.emptySet();
+- SUPPORTS_KEYMANAGER_FACTORY = false;
+- USE_KEYMANAGER_FACTORY = false;
+- SUPPORTED_PROTOCOLS_SET = Collections.emptySet();
+- SUPPORTS_OCSP = false;
+- TLSV13_SUPPORTED = false;
+- IS_BORINGSSL = false;
+- EXTRA_SUPPORTED_TLS_1_3_CIPHERS = EmptyArrays.EMPTY_STRINGS;
+- }
- }
-
- /**
-- * Creates a new instance.
-- *
-- * @param certChainFile an X.509 certificate chain file in PEM format.
-- * {@code null} to use the system default
-- * @deprecated use {@link SslContextBuilder}
+- * Returns a self-signed {@link X509Certificate} for {@code netty.io}.
- */
-- @Deprecated
-- public OpenSslClientContext(File certChainFile) throws SSLException {
-- this(certChainFile, null);
+- static X509Certificate selfSignedCertificate() throws CertificateException {
+- return (X509Certificate) SslContext.X509_CERT_FACTORY.generateCertificate(
+- new ByteArrayInputStream(CERT.getBytes(CharsetUtil.US_ASCII))
+- );
+- }
+-
+- private static boolean doesSupportOcsp() {
+- boolean supportsOcsp = false;
+- if (version() >= 0x10002000L) {
+- long sslCtx = -1;
+- try {
+- sslCtx = SSLContext.make(SSL.SSL_PROTOCOL_TLSV1_2, SSL.SSL_MODE_SERVER);
+- SSLContext.enableOcsp(sslCtx, false);
+- supportsOcsp = true;
+- } catch (Exception ignore) {
+- // ignore
+- } finally {
+- if (sslCtx != -1) {
+- SSLContext.free(sslCtx);
+- }
+- }
+- }
+- return supportsOcsp;
+- }
+- private static boolean doesSupportProtocol(int protocol, int opt) {
+- if (opt == 0) {
+- // If the opt is 0 the protocol is not supported. This is for example the case with BoringSSL and SSLv2.
+- return false;
+- }
+- long sslCtx = -1;
+- try {
+- sslCtx = SSLContext.make(protocol, SSL.SSL_MODE_COMBINED);
+- return true;
+- } catch (Exception ignore) {
+- return false;
+- } finally {
+- if (sslCtx != -1) {
+- SSLContext.free(sslCtx);
+- }
+- }
- }
-
- /**
-- * Creates a new instance.
-- *
-- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
-- * that verifies the certificates sent from servers.
-- * {@code null} to use the default.
-- * @deprecated use {@link SslContextBuilder}
+- * Returns {@code true} if and only if
+- * <a href="https://netty.io/wiki/forked-tomcat-native.html">{@code netty-tcnative}</a> and its OpenSSL support
+- * are available.
- */
-- @Deprecated
-- public OpenSslClientContext(TrustManagerFactory trustManagerFactory) throws SSLException {
-- this(null, trustManagerFactory);
+- public static boolean isAvailable() {
+- return UNAVAILABILITY_CAUSE == null;
- }
-
- /**
-- * Creates a new instance.
+- * Returns {@code true} if the used version of openssl supports
+- * <a href="https://tools.ietf.org/html/rfc7301">ALPN</a>.
- *
-- * @param certChainFile an X.509 certificate chain file in PEM format.
-- * {@code null} to use the system default
-- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
-- * that verifies the certificates sent from servers.
-- * {@code null} to use the default.
-- * @deprecated use {@link SslContextBuilder}
+- * @deprecated use {@link SslProvider#isAlpnSupported(SslProvider)} with {@link SslProvider#OPENSSL}.
- */
- @Deprecated
-- public OpenSslClientContext(File certChainFile, TrustManagerFactory trustManagerFactory) throws SSLException {
-- this(certChainFile, trustManagerFactory, null, null, null, null, null,
-- IdentityCipherSuiteFilter.INSTANCE, null, 0, 0);
+- public static boolean isAlpnSupported() {
+- return version() >= 0x10002000L;
- }
-
- /**
-- * Creates a new instance.
-- *
-- * @param certChainFile an X.509 certificate chain file in PEM format
-- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
-- * that verifies the certificates sent from servers.
-- * {@code null} to use the default..
-- * @param ciphers the cipher suites to enable, in the order of preference.
-- * {@code null} to use the default cipher suites.
-- * @param apn Provides a means to configure parameters related to application protocol negotiation.
-- * @param sessionCacheSize the size of the cache used for storing SSL session objects.
-- * {@code 0} to use the default value.
-- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
-- * {@code 0} to use the default value.
-- * @deprecated use {@link SslContextBuilder}
+- * Returns {@code true} if the used version of OpenSSL supports OCSP stapling.
- */
-- @Deprecated
-- public OpenSslClientContext(File certChainFile, TrustManagerFactory trustManagerFactory, Iterable<String> ciphers,
-- ApplicationProtocolConfig apn, long sessionCacheSize, long sessionTimeout)
-- throws SSLException {
-- this(certChainFile, trustManagerFactory, null, null, null, null, ciphers, IdentityCipherSuiteFilter.INSTANCE,
-- apn, sessionCacheSize, sessionTimeout);
+- public static boolean isOcspSupported() {
+- return SUPPORTS_OCSP;
- }
-
- /**
-- * Creates a new instance.
-- *
-- * @param certChainFile an X.509 certificate chain file in PEM format
-- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
-- * that verifies the certificates sent from servers.
-- * {@code null} to use the default..
-- * @param ciphers the cipher suites to enable, in the order of preference.
-- * {@code null} to use the default cipher suites.
-- * @param cipherFilter a filter to apply over the supplied list of ciphers
-- * @param apn Provides a means to configure parameters related to application protocol negotiation.
-- * @param sessionCacheSize the size of the cache used for storing SSL session objects.
-- * {@code 0} to use the default value.
-- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
-- * {@code 0} to use the default value.
-- * @deprecated use {@link SslContextBuilder}
+- * Returns the version of the used available OpenSSL library or {@code -1} if {@link #isAvailable()}
+- * returns {@code false}.
+- */
+- public static int version() {
+- return isAvailable() ? SSL.version() : -1;
+- }
+-
+- /**
+- * Returns the version string of the used available OpenSSL library or {@code null} if {@link #isAvailable()}
+- * returns {@code false}.
+- */
+- public static String versionString() {
+- return isAvailable() ? SSL.versionString() : null;
+- }
+-
+- /**
+- * Ensure that <a href="https://netty.io/wiki/forked-tomcat-native.html">{@code netty-tcnative}</a> and
+- * its OpenSSL support are available.
+- *
+- * @throws UnsatisfiedLinkError if unavailable
+- */
+- public static void ensureAvailability() {
+- if (UNAVAILABILITY_CAUSE != null) {
+- throw (Error) new UnsatisfiedLinkError(
+- "failed to load the required native library").initCause(UNAVAILABILITY_CAUSE);
+- }
+- }
+-
+- /**
+- * Returns the cause of unavailability of
+- * <a href="https://netty.io/wiki/forked-tomcat-native.html">{@code netty-tcnative}</a> and its OpenSSL support.
+- *
+- * @return the cause if unavailable. {@code null} if available.
+- */
+- public static Throwable unavailabilityCause() {
+- return UNAVAILABILITY_CAUSE;
+- }
+-
+- /**
+- * @deprecated use {@link #availableOpenSslCipherSuites()}
- */
- @Deprecated
-- public OpenSslClientContext(File certChainFile, TrustManagerFactory trustManagerFactory, Iterable<String> ciphers,
-- CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
-- long sessionCacheSize, long sessionTimeout) throws SSLException {
-- this(certChainFile, trustManagerFactory, null, null, null, null,
-- ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout);
+- public static Set<String> availableCipherSuites() {
+- return availableOpenSslCipherSuites();
- }
-
- /**
-- * Creates a new instance.
-- * @param trustCertCollectionFile an X.509 certificate collection file in PEM format.
-- * {@code null} to use the system default
-- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
-- * that verifies the certificates sent from servers.
-- * {@code null} to use the default or the results of parsing
-- * {@code trustCertCollectionFile}
-- * @param keyCertChainFile an X.509 certificate chain file in PEM format.
-- * This provides the public key for mutual authentication.
-- * {@code null} to use the system default
-- * @param keyFile a PKCS#8 private key file in PEM format.
-- * This provides the private key for mutual authentication.
-- * {@code null} for no mutual authentication.
-- * @param keyPassword the password of the {@code keyFile}.
-- * {@code null} if it's not password-protected.
-- * Ignored if {@code keyFile} is {@code null}.
-- * @param keyManagerFactory the {@link KeyManagerFactory} that provides the {@link javax.net.ssl.KeyManager}s
-- * that is used to encrypt data being sent to servers.
-- * {@code null} to use the default or the results of parsing
-- * {@code keyCertChainFile} and {@code keyFile}.
-- * @param ciphers the cipher suites to enable, in the order of preference.
-- * {@code null} to use the default cipher suites.
-- * @param cipherFilter a filter to apply over the supplied list of ciphers
-- * @param apn Application Protocol Negotiator object.
-- * @param sessionCacheSize the size of the cache used for storing SSL session objects.
-- * {@code 0} to use the default value.
-- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
-- * {@code 0} to use the default value.
-- * @deprecated use {@link SslContextBuilder}
+- * Returns all the available OpenSSL cipher suites.
+- * Please note that the returned array may include the cipher suites that are insecure or non-functional.
+- */
+- public static Set<String> availableOpenSslCipherSuites() {
+- return AVAILABLE_OPENSSL_CIPHER_SUITES;
+- }
+-
+- /**
+- * Returns all the available cipher suites (Java-style).
+- * Please note that the returned array may include the cipher suites that are insecure or non-functional.
+- */
+- public static Set<String> availableJavaCipherSuites() {
+- return AVAILABLE_JAVA_CIPHER_SUITES;
+- }
+-
+- /**
+- * Returns {@code true} if and only if the specified cipher suite is available in OpenSSL.
+- * Both Java-style cipher suite and OpenSSL-style cipher suite are accepted.
+- */
+- public static boolean isCipherSuiteAvailable(String cipherSuite) {
+- String converted = CipherSuiteConverter.toOpenSsl(cipherSuite, IS_BORINGSSL);
+- if (converted != null) {
+- cipherSuite = converted;
+- }
+- return AVAILABLE_OPENSSL_CIPHER_SUITES.contains(cipherSuite);
+- }
+-
+- /**
+- * Returns {@code true} if {@link javax.net.ssl.KeyManagerFactory} is supported when using OpenSSL.
+- */
+- public static boolean supportsKeyManagerFactory() {
+- return SUPPORTS_KEYMANAGER_FACTORY;
+- }
+-
+- /**
+- * Always returns {@code true} if {@link #isAvailable()} returns {@code true}.
+- *
+- * @deprecated Will be removed because hostname validation is always done by a
+- * {@link javax.net.ssl.TrustManager} implementation.
- */
- @Deprecated
-- public OpenSslClientContext(File trustCertCollectionFile, TrustManagerFactory trustManagerFactory,
-- File keyCertChainFile, File keyFile, String keyPassword,
-- KeyManagerFactory keyManagerFactory, Iterable<String> ciphers,
-- CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
-- long sessionCacheSize, long sessionTimeout)
-- throws SSLException {
-- this(toX509CertificatesInternal(trustCertCollectionFile), trustManagerFactory,
-- toX509CertificatesInternal(keyCertChainFile), toPrivateKeyInternal(keyFile, keyPassword),
-- keyPassword, keyManagerFactory, ciphers, cipherFilter, apn, null, sessionCacheSize,
-- sessionTimeout, false);
+- public static boolean supportsHostnameValidation() {
+- return isAvailable();
- }
-
-- OpenSslClientContext(X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory,
-- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword,
-- KeyManagerFactory keyManagerFactory, Iterable<String> ciphers,
-- CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, String[] protocols,
-- long sessionCacheSize, long sessionTimeout, boolean enableOcsp)
-- throws SSLException {
-- super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, SSL.SSL_MODE_CLIENT, keyCertChain,
-- ClientAuth.NONE, protocols, false, enableOcsp);
-- boolean success = false;
-- try {
-- sessionContext = newSessionContext(this, ctx, engineMap, trustCertCollection, trustManagerFactory,
-- keyCertChain, key, keyPassword, keyManagerFactory);
-- success = true;
-- } finally {
-- if (!success) {
-- release();
-- }
+- static boolean useKeyManagerFactory() {
+- return USE_KEYMANAGER_FACTORY;
+- }
+-
+- static long memoryAddress(ByteBuf buf) {
+- assert buf.isDirect();
+- return buf.hasMemoryAddress() ? buf.memoryAddress() : Buffer.address(buf.nioBuffer());
+- }
+-
+- private OpenSsl() { }
+-
+- private static void loadTcNative() throws Exception {
+- String os = PlatformDependent.normalizedOs();
+- String arch = PlatformDependent.normalizedArch();
+-
+- Set<String> libNames = new LinkedHashSet<String>(5);
+- String staticLibName = "netty_tcnative";
+-
+- // First, try loading the platform-specific library. Platform-specific
+- // libraries will be available if using a tcnative uber jar.
+- if ("linux".equalsIgnoreCase(os)) {
+- Set<String> classifiers = PlatformDependent.normalizedLinuxClassifiers();
+- for (String classifier : classifiers) {
+- libNames.add(staticLibName + "_" + os + '_' + arch + "_" + classifier);
+- }
+- // generic arch-dependent library
+- libNames.add(staticLibName + "_" + os + '_' + arch);
+-
+- // Fedora SSL lib so naming (libssl.so.10 vs libssl.so.1.0.0).
+- // note: should already be included from the classifiers but if not, we use this as an
+- // additional fallback option here
+- libNames.add(staticLibName + "_" + os + '_' + arch + "_fedora");
+- } else {
+- libNames.add(staticLibName + "_" + os + '_' + arch);
- }
+- libNames.add(staticLibName + "_" + arch);
+- libNames.add(staticLibName);
+-
+- NativeLibraryLoader.loadFirstAvailable(SSLContext.class.getClassLoader(),
+- libNames.toArray(new String[0]));
- }
-
-- @Override
-- public OpenSslSessionContext sessionContext() {
-- return sessionContext;
+- private static boolean initializeTcNative(String engine) throws Exception {
+- return Library.initialize("provided", engine);
- }
-
-- @Override
-- OpenSslKeyMaterialManager keyMaterialManager() {
-- return null;
+- static void releaseIfNeeded(ReferenceCounted counted) {
+- if (counted.refCnt() > 0) {
+- ReferenceCountUtil.safeRelease(counted);
+- }
+- }
+-
+- static boolean isTlsv13Supported() {
+- return TLSV13_SUPPORTED;
+- }
+-
+- static boolean isBoringSSL() {
+- return IS_BORINGSSL;
- }
-}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslContext.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslContext.java
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslCachingKeyMaterialProvider.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslCachingKeyMaterialProvider.java
deleted file mode 100644
-index c4ca6b5..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/OpenSslContext.java
+index 07b67d9fa7..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslCachingKeyMaterialProvider.java
+++ /dev/null
-@@ -1,58 +0,0 @@
+@@ -1,79 +0,0 @@
-/*
-- * Copyright 2014 The Netty Project
+- * Copyright 2018 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
@@ -933,53 +1356,74 @@ index c4ca6b5..0000000
-
-import io.netty.buffer.ByteBufAllocator;
-
--import java.security.cert.Certificate;
--
--import javax.net.ssl.SSLEngine;
--import javax.net.ssl.SSLException;
+-import javax.net.ssl.X509KeyManager;
+-import java.util.Iterator;
+-import java.util.concurrent.ConcurrentHashMap;
+-import java.util.concurrent.ConcurrentMap;
-
-/**
-- * This class will use a finalizer to ensure native resources are automatically cleaned up. To avoid finalizers
-- * and manually release the native memory see {@link ReferenceCountedOpenSslContext}.
+- * {@link OpenSslKeyMaterialProvider} that will cache the {@link OpenSslKeyMaterial} to reduce the overhead
+- * of parsing the chain and the key for generation of the material.
- */
--public abstract class OpenSslContext extends ReferenceCountedOpenSslContext {
-- OpenSslContext(Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apnCfg,
-- long sessionCacheSize, long sessionTimeout, int mode, Certificate[] keyCertChain,
-- ClientAuth clientAuth, String[] protocols, boolean startTls, boolean enableOcsp)
-- throws SSLException {
-- super(ciphers, cipherFilter, apnCfg, sessionCacheSize, sessionTimeout, mode, keyCertChain,
-- clientAuth, protocols, startTls, enableOcsp, false);
-- }
+-final class OpenSslCachingKeyMaterialProvider extends OpenSslKeyMaterialProvider {
-
-- OpenSslContext(Iterable<String> ciphers, CipherSuiteFilter cipherFilter,
-- OpenSslApplicationProtocolNegotiator apn, long sessionCacheSize,
-- long sessionTimeout, int mode, Certificate[] keyCertChain,
-- ClientAuth clientAuth, String[] protocols, boolean startTls,
-- boolean enableOcsp) throws SSLException {
-- super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, mode, keyCertChain, clientAuth, protocols,
-- startTls, enableOcsp, false);
+- private final int maxCachedEntries;
+- private volatile boolean full;
+- private final ConcurrentMap<String, OpenSslKeyMaterial> cache = new ConcurrentHashMap<String, OpenSslKeyMaterial>();
+-
+- OpenSslCachingKeyMaterialProvider(X509KeyManager keyManager, String password, int maxCachedEntries) {
+- super(keyManager, password);
+- this.maxCachedEntries = maxCachedEntries;
- }
-
- @Override
-- final SSLEngine newEngine0(ByteBufAllocator alloc, String peerHost, int peerPort) {
-- return new OpenSslEngine(this, alloc, peerHost, peerPort);
+- OpenSslKeyMaterial chooseKeyMaterial(ByteBufAllocator allocator, String alias) throws Exception {
+- OpenSslKeyMaterial material = cache.get(alias);
+- if (material == null) {
+- material = super.chooseKeyMaterial(allocator, alias);
+- if (material == null) {
+- // No keymaterial should be used.
+- return null;
+- }
+-
+- if (full) {
+- return material;
+- }
+- if (cache.size() > maxCachedEntries) {
+- full = true;
+- // Do not cache...
+- return material;
+- }
+- OpenSslKeyMaterial old = cache.putIfAbsent(alias, material);
+- if (old != null) {
+- material.release();
+- material = old;
+- }
+- }
+- // We need to call retain() as we want to always have at least a refCnt() of 1 before destroy() was called.
+- return material.retain();
- }
-
- @Override
-- @SuppressWarnings("FinalizeDeclaration")
-- protected final void finalize() throws Throwable {
-- super.finalize();
-- OpenSsl.releaseIfNeeded(this);
+- void destroy() {
+- // Remove and release all entries.
+- do {
+- Iterator<OpenSslKeyMaterial> iterator = cache.values().iterator();
+- while (iterator.hasNext()) {
+- iterator.next().release();
+- iterator.remove();
+- }
+- } while (!cache.isEmpty());
- }
-}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslEngine.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslEngine.java
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslCachingX509KeyManagerFactory.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslCachingX509KeyManagerFactory.java
deleted file mode 100644
-index cbc7ee4..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/OpenSslEngine.java
+index 7f67bc8198..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslCachingX509KeyManagerFactory.java
+++ /dev/null
-@@ -1,40 +0,0 @@
+@@ -1,81 +0,0 @@
-/*
-- * Copyright 2014 The Netty Project
+- * Copyright 2018 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
@@ -995,37 +1439,78 @@ index cbc7ee4..0000000
- */
-package io.netty.handler.ssl;
-
--import io.netty.buffer.ByteBufAllocator;
+-import io.netty.util.internal.ObjectUtil;
-
--import javax.net.ssl.SSLEngine;
+-import javax.net.ssl.KeyManager;
+-import javax.net.ssl.KeyManagerFactory;
+-import javax.net.ssl.KeyManagerFactorySpi;
+-import javax.net.ssl.ManagerFactoryParameters;
+-import javax.net.ssl.X509ExtendedKeyManager;
+-import javax.net.ssl.X509KeyManager;
+-import java.security.InvalidAlgorithmParameterException;
+-import java.security.KeyStore;
+-import java.security.KeyStoreException;
+-import java.security.NoSuchAlgorithmException;
+-import java.security.PrivateKey;
+-import java.security.UnrecoverableKeyException;
+-import java.security.cert.X509Certificate;
-
-/**
-- * Implements a {@link SSLEngine} using
-- * <a href="https://www.openssl.org/docs/crypto/BIO_s_bio.html#EXAMPLE">OpenSSL BIO abstractions</a>.
-- * <p>
-- * This class will use a finalizer to ensure native resources are automatically cleaned up. To avoid finalizers
-- * and manually release the native memory see {@link ReferenceCountedOpenSslEngine}.
+- * Wraps another {@link KeyManagerFactory} and caches its chains / certs for an alias for better performance when using
+- * {@link SslProvider#OPENSSL} or {@link SslProvider#OPENSSL_REFCNT}.
+- *
+- * Because of the caching its important that the wrapped {@link KeyManagerFactory}s {@link X509KeyManager}s always
+- * return the same {@link X509Certificate} chain and {@link PrivateKey} for the same alias.
- */
--public final class OpenSslEngine extends ReferenceCountedOpenSslEngine {
-- OpenSslEngine(OpenSslContext context, ByteBufAllocator alloc, String peerHost, int peerPort) {
-- super(context, alloc, peerHost, peerPort, false);
+-public final class OpenSslCachingX509KeyManagerFactory extends KeyManagerFactory {
+-
+- private final int maxCachedEntries;
+-
+- public OpenSslCachingX509KeyManagerFactory(final KeyManagerFactory factory) {
+- this(factory, 1024);
- }
-
-- @Override
-- @SuppressWarnings("FinalizeDeclaration")
-- protected void finalize() throws Throwable {
-- super.finalize();
-- OpenSsl.releaseIfNeeded(this);
+- public OpenSslCachingX509KeyManagerFactory(final KeyManagerFactory factory, int maxCachedEntries) {
+- super(new KeyManagerFactorySpi() {
+- @Override
+- protected void engineInit(KeyStore keyStore, char[] chars)
+- throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
+- factory.init(keyStore, chars);
+- }
+-
+- @Override
+- protected void engineInit(ManagerFactoryParameters managerFactoryParameters)
+- throws InvalidAlgorithmParameterException {
+- factory.init(managerFactoryParameters);
+- }
+-
+- @Override
+- protected KeyManager[] engineGetKeyManagers() {
+- return factory.getKeyManagers();
+- }
+- }, factory.getProvider(), factory.getAlgorithm());
+- this.maxCachedEntries = ObjectUtil.checkPositive(maxCachedEntries, "maxCachedEntries");
+- }
+-
+- OpenSslKeyMaterialProvider newProvider(String password) {
+- X509KeyManager keyManager = ReferenceCountedOpenSslContext.chooseX509KeyManager(getKeyManagers());
+- if ("sun.security.ssl.X509KeyManagerImpl".equals(keyManager.getClass().getName())) {
+- // Don't do caching if X509KeyManagerImpl is used as the returned aliases are not stable and will change
+- // between invocations.
+- return new OpenSslKeyMaterialProvider(keyManager, password);
+- }
+- return new OpenSslCachingKeyMaterialProvider(
+- ReferenceCountedOpenSslContext.chooseX509KeyManager(getKeyManagers()), password, maxCachedEntries);
- }
-}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslEngineMap.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslEngineMap.java
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslCertificateException.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslCertificateException.java
deleted file mode 100644
-index 02131b4..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/OpenSslEngineMap.java
+index f20b2d3ba0..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslCertificateException.java
+++ /dev/null
-@@ -1,35 +0,0 @@
+@@ -1,81 +0,0 @@
-/*
-- * Copyright 2014 The Netty Project
+- * Copyright 2016 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
@@ -1041,261 +1526,76 @@ index 02131b4..0000000
- */
-package io.netty.handler.ssl;
-
--interface OpenSslEngineMap {
+-import io.netty.internal.tcnative.CertificateVerifier;
-
-- /**
-- * Remove the {@link OpenSslEngine} with the given {@code ssl} address and
-- * return it.
-- */
-- ReferenceCountedOpenSslEngine remove(long ssl);
--
-- /**
-- * Add a {@link OpenSslEngine} to this {@link OpenSslEngineMap}.
-- */
-- void add(ReferenceCountedOpenSslEngine engine);
--
-- /**
-- * Get the {@link OpenSslEngine} for the given {@code ssl} address.
-- */
-- ReferenceCountedOpenSslEngine get(long ssl);
--}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslExtendedKeyMaterialManager.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslExtendedKeyMaterialManager.java
-deleted file mode 100644
-index 38f6a7f..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/OpenSslExtendedKeyMaterialManager.java
-+++ /dev/null
-@@ -1,40 +0,0 @@
--/*
-- * Copyright 2016 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
--
--import javax.net.ssl.X509ExtendedKeyManager;
--import javax.security.auth.x500.X500Principal;
--
--final class OpenSslExtendedKeyMaterialManager extends OpenSslKeyMaterialManager {
--
-- private final X509ExtendedKeyManager keyManager;
--
-- OpenSslExtendedKeyMaterialManager(X509ExtendedKeyManager keyManager, String password) {
-- super(keyManager, password);
-- this.keyManager = keyManager;
-- }
--
-- @Override
-- protected String chooseClientAlias(ReferenceCountedOpenSslEngine engine, String[] keyTypes,
-- X500Principal[] issuer) {
-- return keyManager.chooseEngineClientAlias(keyTypes, issuer, engine);
-- }
--
-- @Override
-- protected String chooseServerAlias(ReferenceCountedOpenSslEngine engine, String type) {
-- return keyManager.chooseEngineServerAlias(type, null, engine);
-- }
--}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialManager.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialManager.java
-deleted file mode 100644
-index 2e48e8b..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialManager.java
-+++ /dev/null
-@@ -1,179 +0,0 @@
--/*
-- * Copyright 2016 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
--
--import io.netty.buffer.ByteBufAllocator;
--import io.netty.internal.tcnative.CertificateRequestedCallback;
--import io.netty.internal.tcnative.SSL;
--
--import javax.net.ssl.SSLException;
--import javax.net.ssl.X509KeyManager;
--import javax.security.auth.x500.X500Principal;
--import java.security.PrivateKey;
--import java.security.cert.X509Certificate;
--import java.util.HashMap;
--import java.util.HashSet;
--import java.util.Map;
--import java.util.Set;
--
--import static io.netty.handler.ssl.ReferenceCountedOpenSslContext.freeBio;
--import static io.netty.handler.ssl.ReferenceCountedOpenSslContext.toBIO;
+-import java.security.cert.CertificateException;
-
-/**
-- * Manages key material for {@link OpenSslEngine}s and so set the right {@link PrivateKey}s and
-- * {@link X509Certificate}s.
+- * A special {@link CertificateException} which allows to specify which error code is included in the
+- * SSL Record. This only work when {@link SslProvider#OPENSSL} or {@link SslProvider#OPENSSL_REFCNT} is used.
- */
--class OpenSslKeyMaterialManager {
--
-- // Code in this class is inspired by code of conscrypts:
-- // - https://android.googlesource.com/platform/external/
-- // conscrypt/+/master/src/main/java/org/conscrypt/OpenSSLEngineImpl.java
-- // - https://android.googlesource.com/platform/external/
-- // conscrypt/+/master/src/main/java/org/conscrypt/SSLParametersImpl.java
-- //
-- static final String KEY_TYPE_RSA = "RSA";
-- static final String KEY_TYPE_DH_RSA = "DH_RSA";
-- static final String KEY_TYPE_EC = "EC";
-- static final String KEY_TYPE_EC_EC = "EC_EC";
-- static final String KEY_TYPE_EC_RSA = "EC_RSA";
--
-- // key type mappings for types.
-- private static final Map<String, String> KEY_TYPES = new HashMap<String, String>();
-- static {
-- KEY_TYPES.put("RSA", KEY_TYPE_RSA);
-- KEY_TYPES.put("DHE_RSA", KEY_TYPE_RSA);
-- KEY_TYPES.put("ECDHE_RSA", KEY_TYPE_RSA);
-- KEY_TYPES.put("ECDHE_ECDSA", KEY_TYPE_EC);
-- KEY_TYPES.put("ECDH_RSA", KEY_TYPE_EC_RSA);
-- KEY_TYPES.put("ECDH_ECDSA", KEY_TYPE_EC_EC);
-- KEY_TYPES.put("DH_RSA", KEY_TYPE_DH_RSA);
-- }
+-public final class OpenSslCertificateException extends CertificateException {
+- private static final long serialVersionUID = 5542675253797129798L;
-
-- private final X509KeyManager keyManager;
-- private final String password;
+- private final int errorCode;
-
-- OpenSslKeyMaterialManager(X509KeyManager keyManager, String password) {
-- this.keyManager = keyManager;
-- this.password = password;
+- /**
+- * Construct a new exception with the
+- * <a href="https://www.openssl.org/docs/manmaster/apps/verify.html">error code</a>.
+- */
+- public OpenSslCertificateException(int errorCode) {
+- this((String) null, errorCode);
- }
-
-- void setKeyMaterial(ReferenceCountedOpenSslEngine engine) throws SSLException {
-- long ssl = engine.sslPointer();
-- String[] authMethods = SSL.authenticationMethods(ssl);
-- Set<String> aliases = new HashSet<String>(authMethods.length);
-- for (String authMethod : authMethods) {
-- String type = KEY_TYPES.get(authMethod);
-- if (type != null) {
-- String alias = chooseServerAlias(engine, type);
-- if (alias != null && aliases.add(alias)) {
-- setKeyMaterial(ssl, alias);
-- }
-- }
-- }
+- /**
+- * Construct a new exception with the msg and
+- * <a href="https://www.openssl.org/docs/manmaster/apps/verify.html">error code</a> .
+- */
+- public OpenSslCertificateException(String msg, int errorCode) {
+- super(msg);
+- this.errorCode = checkErrorCode(errorCode);
- }
-
-- CertificateRequestedCallback.KeyMaterial keyMaterial(ReferenceCountedOpenSslEngine engine, String[] keyTypes,
-- X500Principal[] issuer) throws SSLException {
-- String alias = chooseClientAlias(engine, keyTypes, issuer);
-- long keyBio = 0;
-- long keyCertChainBio = 0;
-- long pkey = 0;
-- long certChain = 0;
--
-- try {
-- // TODO: Should we cache these and so not need to do a memory copy all the time ?
-- X509Certificate[] certificates = keyManager.getCertificateChain(alias);
-- if (certificates == null || certificates.length == 0) {
-- return null;
-- }
--
-- PrivateKey key = keyManager.getPrivateKey(alias);
-- keyCertChainBio = toBIO(certificates);
-- certChain = SSL.parseX509Chain(keyCertChainBio);
-- if (key != null) {
-- keyBio = toBIO(key);
-- pkey = SSL.parsePrivateKey(keyBio, password);
-- }
-- CertificateRequestedCallback.KeyMaterial material = new CertificateRequestedCallback.KeyMaterial(
-- certChain, pkey);
--
-- // Reset to 0 so we do not free these. This is needed as the client certificate callback takes ownership
-- // of both the key and the certificate if they are returned from this method, and thus must not
-- // be freed here.
-- certChain = pkey = 0;
-- return material;
-- } catch (SSLException e) {
-- throw e;
-- } catch (Exception e) {
-- throw new SSLException(e);
-- } finally {
-- freeBio(keyBio);
-- freeBio(keyCertChainBio);
-- SSL.freePrivateKey(pkey);
-- SSL.freeX509Chain(certChain);
-- }
+- /**
+- * Construct a new exception with the msg, cause and
+- * <a href="https://www.openssl.org/docs/manmaster/apps/verify.html">error code</a> .
+- */
+- public OpenSslCertificateException(String message, Throwable cause, int errorCode) {
+- super(message, cause);
+- this.errorCode = checkErrorCode(errorCode);
- }
-
-- private void setKeyMaterial(long ssl, String alias) throws SSLException {
-- long keyBio = 0;
-- long keyCertChainBio = 0;
-- long keyCertChainBio2 = 0;
--
-- try {
-- // TODO: Should we cache these and so not need to do a memory copy all the time ?
-- X509Certificate[] certificates = keyManager.getCertificateChain(alias);
-- if (certificates == null || certificates.length == 0) {
-- return;
-- }
--
-- PrivateKey key = keyManager.getPrivateKey(alias);
--
-- // Only encode one time
-- PemEncoded encoded = PemX509Certificate.toPEM(ByteBufAllocator.DEFAULT, true, certificates);
-- try {
-- keyCertChainBio = toBIO(ByteBufAllocator.DEFAULT, encoded.retain());
-- keyCertChainBio2 = toBIO(ByteBufAllocator.DEFAULT, encoded.retain());
--
-- if (key != null) {
-- keyBio = toBIO(key);
-- }
-- SSL.setCertificateBio(ssl, keyCertChainBio, keyBio, password);
--
-- // We may have more then one cert in the chain so add all of them now.
-- SSL.setCertificateChainBio(ssl, keyCertChainBio2, true);
-- } finally {
-- encoded.release();
-- }
-- } catch (SSLException e) {
-- throw e;
-- } catch (Exception e) {
-- throw new SSLException(e);
-- } finally {
-- freeBio(keyBio);
-- freeBio(keyCertChainBio);
-- freeBio(keyCertChainBio2);
-- }
+- /**
+- * Construct a new exception with the cause and
+- * <a href="https://www.openssl.org/docs/manmaster/apps/verify.html">error code</a> .
+- */
+- public OpenSslCertificateException(Throwable cause, int errorCode) {
+- this(null, cause, errorCode);
- }
-
-- protected String chooseClientAlias(@SuppressWarnings("unused") ReferenceCountedOpenSslEngine engine,
-- String[] keyTypes, X500Principal[] issuer) {
-- return keyManager.chooseClientAlias(keyTypes, issuer, null);
+- /**
+- * Return the <a href="https://www.openssl.org/docs/man1.0.2/apps/verify.html">error code</a> to use.
+- */
+- public int errorCode() {
+- return errorCode;
- }
-
-- protected String chooseServerAlias(@SuppressWarnings("unused") ReferenceCountedOpenSslEngine engine, String type) {
-- return keyManager.chooseServerAlias(type, null, null);
+- private static int checkErrorCode(int errorCode) {
+- // Call OpenSsl.isAvailable() to ensure we try to load the native lib as CertificateVerifier.isValid(...)
+- // will depend on it. If loading fails we will just skip the validation.
+- if (OpenSsl.isAvailable() && !CertificateVerifier.isValid(errorCode)) {
+- throw new IllegalArgumentException("errorCode '" + errorCode +
+- "' invalid, see https://www.openssl.org/docs/man1.0.2/apps/verify.html.");
+- }
+- return errorCode;
- }
-}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerContext.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslServerContext.java
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslClientContext.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslClientContext.java
deleted file mode 100644
-index f57434b..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerContext.java
+index 7f9b39a8dd..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslClientContext.java
+++ /dev/null
-@@ -1,373 +0,0 @@
+@@ -1,208 +0,0 @@
-/*
- * Copyright 2014 The Netty Project
- *
@@ -1313,143 +1613,88 @@ index f57434b..0000000
- */
-package io.netty.handler.ssl;
-
--import io.netty.handler.ssl.ReferenceCountedOpenSslServerContext.ServerContext;
-import io.netty.internal.tcnative.SSL;
-
-import java.io.File;
+-import java.security.KeyStore;
-import java.security.PrivateKey;
-import java.security.cert.X509Certificate;
-
--import javax.net.ssl.KeyManager;
-import javax.net.ssl.KeyManagerFactory;
-import javax.net.ssl.SSLException;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.TrustManagerFactory;
-
--import static io.netty.handler.ssl.ReferenceCountedOpenSslServerContext.newSessionContext;
+-import static io.netty.handler.ssl.ReferenceCountedOpenSslClientContext.newSessionContext;
-
-/**
-- * A server-side {@link SslContext} which uses OpenSSL's SSL/TLS implementation.
+- * A client-side {@link SslContext} which uses OpenSSL's SSL/TLS implementation.
- * <p>This class will use a finalizer to ensure native resources are automatically cleaned up. To avoid finalizers
-- * and manually release the native memory see {@link ReferenceCountedOpenSslServerContext}.
+- * and manually release the native memory see {@link ReferenceCountedOpenSslClientContext}.
- */
--public final class OpenSslServerContext extends OpenSslContext {
-- private final OpenSslServerSessionContext sessionContext;
-- private final OpenSslKeyMaterialManager keyMaterialManager;
+-public final class OpenSslClientContext extends OpenSslContext {
+- private final OpenSslSessionContext sessionContext;
-
- /**
- * Creates a new instance.
-- *
-- * @param certChainFile an X.509 certificate chain file in PEM format
-- * @param keyFile a PKCS#8 private key file in PEM format
- * @deprecated use {@link SslContextBuilder}
- */
- @Deprecated
-- public OpenSslServerContext(File certChainFile, File keyFile) throws SSLException {
-- this(certChainFile, keyFile, null);
+- public OpenSslClientContext() throws SSLException {
+- this(null, null, null, null, null, null, null, IdentityCipherSuiteFilter.INSTANCE, null, 0, 0);
- }
-
- /**
- * Creates a new instance.
- *
-- * @param certChainFile an X.509 certificate chain file in PEM format
-- * @param keyFile a PKCS#8 private key file in PEM format
-- * @param keyPassword the password of the {@code keyFile}.
-- * {@code null} if it's not password-protected.
+- * @param certChainFile an X.509 certificate chain file in PEM format.
+- * {@code null} to use the system default
- * @deprecated use {@link SslContextBuilder}
- */
- @Deprecated
-- public OpenSslServerContext(File certChainFile, File keyFile, String keyPassword) throws SSLException {
-- this(certChainFile, keyFile, keyPassword, null, IdentityCipherSuiteFilter.INSTANCE,
-- ApplicationProtocolConfig.DISABLED, 0, 0);
+- public OpenSslClientContext(File certChainFile) throws SSLException {
+- this(certChainFile, null);
- }
-
- /**
- * Creates a new instance.
- *
-- * @param certChainFile an X.509 certificate chain file in PEM format
-- * @param keyFile a PKCS#8 private key file in PEM format
-- * @param keyPassword the password of the {@code keyFile}.
-- * {@code null} if it's not password-protected.
-- * @param ciphers the cipher suites to enable, in the order of preference.
-- * {@code null} to use the default cipher suites.
-- * @param apn Provides a means to configure parameters related to application protocol negotiation.
-- * @param sessionCacheSize the size of the cache used for storing SSL session objects.
-- * {@code 0} to use the default value.
-- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
-- * {@code 0} to use the default value.
-- * @deprecated use {@link SslContextBuilder}
-- */
-- @Deprecated
-- public OpenSslServerContext(
-- File certChainFile, File keyFile, String keyPassword,
-- Iterable<String> ciphers, ApplicationProtocolConfig apn,
-- long sessionCacheSize, long sessionTimeout) throws SSLException {
-- this(certChainFile, keyFile, keyPassword, ciphers, IdentityCipherSuiteFilter.INSTANCE,
-- apn, sessionCacheSize, sessionTimeout);
-- }
--
-- /**
-- * Creates a new instance.
-- *
-- * @param certChainFile an X.509 certificate chain file in PEM format
-- * @param keyFile a PKCS#8 private key file in PEM format
-- * @param keyPassword the password of the {@code keyFile}.
-- * {@code null} if it's not password-protected.
-- * @param ciphers the cipher suites to enable, in the order of preference.
-- * {@code null} to use the default cipher suites.
-- * @param nextProtocols the application layer protocols to accept, in the order of preference.
-- * {@code null} to disable TLS NPN/ALPN extension.
-- * @param sessionCacheSize the size of the cache used for storing SSL session objects.
-- * {@code 0} to use the default value.
-- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
-- * {@code 0} to use the default value.
+- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
+- * that verifies the certificates sent from servers.
+- * {@code null} to use the default.
- * @deprecated use {@link SslContextBuilder}
- */
- @Deprecated
-- public OpenSslServerContext(
-- File certChainFile, File keyFile, String keyPassword,
-- Iterable<String> ciphers, Iterable<String> nextProtocols,
-- long sessionCacheSize, long sessionTimeout) throws SSLException {
-- this(certChainFile, keyFile, keyPassword, ciphers,
-- toApplicationProtocolConfig(nextProtocols), sessionCacheSize, sessionTimeout);
+- public OpenSslClientContext(TrustManagerFactory trustManagerFactory) throws SSLException {
+- this(null, trustManagerFactory);
- }
-
- /**
- * Creates a new instance.
- *
-- * @param certChainFile an X.509 certificate chain file in PEM format
-- * @param keyFile a PKCS#8 private key file in PEM format
-- * @param keyPassword the password of the {@code keyFile}.
-- * {@code null} if it's not password-protected.
-- * @param ciphers the cipher suites to enable, in the order of preference.
-- * {@code null} to use the default cipher suites.
-- * @param config Application protocol config.
-- * @param sessionCacheSize the size of the cache used for storing SSL session objects.
-- * {@code 0} to use the default value.
-- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
-- * {@code 0} to use the default value.
+- * @param certChainFile an X.509 certificate chain file in PEM format.
+- * {@code null} to use the system default
+- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
+- * that verifies the certificates sent from servers.
+- * {@code null} to use the default.
- * @deprecated use {@link SslContextBuilder}
- */
- @Deprecated
-- public OpenSslServerContext(
-- File certChainFile, File keyFile, String keyPassword, TrustManagerFactory trustManagerFactory,
-- Iterable<String> ciphers, ApplicationProtocolConfig config,
-- long sessionCacheSize, long sessionTimeout) throws SSLException {
-- this(certChainFile, keyFile, keyPassword, trustManagerFactory, ciphers,
-- toNegotiator(config), sessionCacheSize, sessionTimeout);
+- public OpenSslClientContext(File certChainFile, TrustManagerFactory trustManagerFactory) throws SSLException {
+- this(certChainFile, trustManagerFactory, null, null, null, null, null,
+- IdentityCipherSuiteFilter.INSTANCE, null, 0, 0);
- }
-
- /**
- * Creates a new instance.
- *
- * @param certChainFile an X.509 certificate chain file in PEM format
-- * @param keyFile a PKCS#8 private key file in PEM format
-- * @param keyPassword the password of the {@code keyFile}.
-- * {@code null} if it's not password-protected.
+- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
+- * that verifies the certificates sent from servers.
+- * {@code null} to use the default..
- * @param ciphers the cipher suites to enable, in the order of preference.
- * {@code null} to use the default cipher suites.
-- * @param apn Application protocol negotiator.
+- * @param apn Provides a means to configure parameters related to application protocol negotiation.
- * @param sessionCacheSize the size of the cache used for storing SSL session objects.
- * {@code 0} to use the default value.
- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
@@ -1457,21 +1702,20 @@ index f57434b..0000000
- * @deprecated use {@link SslContextBuilder}
- */
- @Deprecated
-- public OpenSslServerContext(
-- File certChainFile, File keyFile, String keyPassword, TrustManagerFactory trustManagerFactory,
-- Iterable<String> ciphers, OpenSslApplicationProtocolNegotiator apn,
-- long sessionCacheSize, long sessionTimeout) throws SSLException {
-- this(null, trustManagerFactory, certChainFile, keyFile, keyPassword, null,
-- ciphers, null, apn, sessionCacheSize, sessionTimeout);
+- public OpenSslClientContext(File certChainFile, TrustManagerFactory trustManagerFactory, Iterable<String> ciphers,
+- ApplicationProtocolConfig apn, long sessionCacheSize, long sessionTimeout)
+- throws SSLException {
+- this(certChainFile, trustManagerFactory, null, null, null, null, ciphers, IdentityCipherSuiteFilter.INSTANCE,
+- apn, sessionCacheSize, sessionTimeout);
- }
-
- /**
- * Creates a new instance.
- *
- * @param certChainFile an X.509 certificate chain file in PEM format
-- * @param keyFile a PKCS#8 private key file in PEM format
-- * @param keyPassword the password of the {@code keyFile}.
-- * {@code null} if it's not password-protected.
+- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
+- * that verifies the certificates sent from servers.
+- * {@code null} to use the default..
- * @param ciphers the cipher suites to enable, in the order of preference.
- * {@code null} to use the default cipher suites.
- * @param cipherFilter a filter to apply over the supplied list of ciphers
@@ -1483,129 +1727,38 @@ index f57434b..0000000
- * @deprecated use {@link SslContextBuilder}
- */
- @Deprecated
-- public OpenSslServerContext(
-- File certChainFile, File keyFile, String keyPassword,
-- Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
-- long sessionCacheSize, long sessionTimeout) throws SSLException {
-- this(null, null, certChainFile, keyFile, keyPassword, null,
+- public OpenSslClientContext(File certChainFile, TrustManagerFactory trustManagerFactory, Iterable<String> ciphers,
+- CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
+- long sessionCacheSize, long sessionTimeout) throws SSLException {
+- this(certChainFile, trustManagerFactory, null, null, null, null,
- ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout);
- }
-
- /**
- * Creates a new instance.
-- *
- * @param trustCertCollectionFile an X.509 certificate collection file in PEM format.
-- * This provides the certificate collection used for mutual authentication.
- * {@code null} to use the system default
- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
-- * that verifies the certificates sent from clients.
+- * that verifies the certificates sent from servers.
- * {@code null} to use the default or the results of parsing
-- * {@code trustCertCollectionFile}.
-- * @param keyCertChainFile an X.509 certificate chain file in PEM format
-- * @param keyFile a PKCS#8 private key file in PEM format
-- * @param keyPassword the password of the {@code keyFile}.
-- * {@code null} if it's not password-protected.
-- * @param keyManagerFactory the {@link KeyManagerFactory} that provides the {@link KeyManager}s
-- * that is used to encrypt data being sent to clients.
-- * {@code null} to use the default or the results of parsing
-- * {@code keyCertChainFile} and {@code keyFile}.
-- * @param ciphers the cipher suites to enable, in the order of preference.
-- * {@code null} to use the default cipher suites.
-- * @param cipherFilter a filter to apply over the supplied list of ciphers
-- * Only required if {@code provider} is {@link SslProvider#JDK}
-- * @param config Provides a means to configure parameters related to application protocol negotiation.
-- * @param sessionCacheSize the size of the cache used for storing SSL session objects.
-- * {@code 0} to use the default value.
-- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
-- * {@code 0} to use the default value.
-- * @deprecated use {@link SslContextBuilder}
-- */
-- @Deprecated
-- public OpenSslServerContext(
-- File trustCertCollectionFile, TrustManagerFactory trustManagerFactory,
-- File keyCertChainFile, File keyFile, String keyPassword, KeyManagerFactory keyManagerFactory,
-- Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig config,
-- long sessionCacheSize, long sessionTimeout) throws SSLException {
-- this(trustCertCollectionFile, trustManagerFactory, keyCertChainFile, keyFile, keyPassword, keyManagerFactory,
-- ciphers, cipherFilter, toNegotiator(config), sessionCacheSize, sessionTimeout);
-- }
--
-- /**
-- * Creates a new instance.
-- *
-- * @param certChainFile an X.509 certificate chain file in PEM format
-- * @param keyFile a PKCS#8 private key file in PEM format
-- * @param keyPassword the password of the {@code keyFile}.
-- * {@code null} if it's not password-protected.
-- * @param ciphers the cipher suites to enable, in the order of preference.
-- * {@code null} to use the default cipher suites.
-- * @param cipherFilter a filter to apply over the supplied list of ciphers
-- * @param config Application protocol config.
-- * @param sessionCacheSize the size of the cache used for storing SSL session objects.
-- * {@code 0} to use the default value.
-- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
-- * {@code 0} to use the default value.
-- * @deprecated use {@link SslContextBuilder}
-- */
-- @Deprecated
-- public OpenSslServerContext(File certChainFile, File keyFile, String keyPassword,
-- TrustManagerFactory trustManagerFactory, Iterable<String> ciphers,
-- CipherSuiteFilter cipherFilter, ApplicationProtocolConfig config,
-- long sessionCacheSize, long sessionTimeout) throws SSLException {
-- this(null, trustManagerFactory, certChainFile, keyFile, keyPassword, null, ciphers, cipherFilter,
-- toNegotiator(config), sessionCacheSize, sessionTimeout);
-- }
--
-- /**
-- * Creates a new instance.
-- *
-- * @param certChainFile an X.509 certificate chain file in PEM format
-- * @param keyFile a PKCS#8 private key file in PEM format
-- * @param keyPassword the password of the {@code keyFile}.
-- * {@code null} if it's not password-protected.
-- * @param ciphers the cipher suites to enable, in the order of preference.
-- * {@code null} to use the default cipher suites.
-- * @param cipherFilter a filter to apply over the supplied list of ciphers
-- * @param apn Application protocol negotiator.
-- * @param sessionCacheSize the size of the cache used for storing SSL session objects.
-- * {@code 0} to use the default value.
-- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
-- * {@code 0} to use the default value.
-- * @deprecated use {@link SslContextBuilder}}
-- */
-- @Deprecated
-- public OpenSslServerContext(
-- File certChainFile, File keyFile, String keyPassword, TrustManagerFactory trustManagerFactory,
-- Iterable<String> ciphers, CipherSuiteFilter cipherFilter, OpenSslApplicationProtocolNegotiator apn,
-- long sessionCacheSize, long sessionTimeout) throws SSLException {
-- this(null, trustManagerFactory, certChainFile, keyFile, keyPassword, null, ciphers, cipherFilter,
-- apn, sessionCacheSize, sessionTimeout);
-- }
--
-- /**
-- * Creates a new instance.
-- *
-- *
-- * @param trustCertCollectionFile an X.509 certificate collection file in PEM format.
-- * This provides the certificate collection used for mutual authentication.
+- * {@code trustCertCollectionFile}
+- * @param keyCertChainFile an X.509 certificate chain file in PEM format.
+- * This provides the public key for mutual authentication.
- * {@code null} to use the system default
-- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
-- * that verifies the certificates sent from clients.
-- * {@code null} to use the default or the results of parsing
-- * {@code trustCertCollectionFile}.
-- * @param keyCertChainFile an X.509 certificate chain file in PEM format
-- * @param keyFile a PKCS#8 private key file in PEM format
+- * @param keyFile a PKCS#8 private key file in PEM format.
+- * This provides the private key for mutual authentication.
+- * {@code null} for no mutual authentication.
- * @param keyPassword the password of the {@code keyFile}.
- * {@code null} if it's not password-protected.
-- * @param keyManagerFactory the {@link KeyManagerFactory} that provides the {@link KeyManager}s
-- * that is used to encrypt data being sent to clients.
+- * Ignored if {@code keyFile} is {@code null}.
+- * @param keyManagerFactory the {@link KeyManagerFactory} that provides the {@link javax.net.ssl.KeyManager}s
+- * that is used to encrypt data being sent to servers.
- * {@code null} to use the default or the results of parsing
- * {@code keyCertChainFile} and {@code keyFile}.
- * @param ciphers the cipher suites to enable, in the order of preference.
- * {@code null} to use the default cipher suites.
- * @param cipherFilter a filter to apply over the supplied list of ciphers
-- * Only required if {@code provider} is {@link SslProvider#JDK}
-- * @param apn Application Protocol Negotiator object
+- * @param apn Application Protocol Negotiator object.
- * @param sessionCacheSize the size of the cache used for storing SSL session objects.
- * {@code 0} to use the default value.
- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
@@ -1613,44 +1766,31 @@ index f57434b..0000000
- * @deprecated use {@link SslContextBuilder}
- */
- @Deprecated
-- public OpenSslServerContext(
-- File trustCertCollectionFile, TrustManagerFactory trustManagerFactory,
-- File keyCertChainFile, File keyFile, String keyPassword, KeyManagerFactory keyManagerFactory,
-- Iterable<String> ciphers, CipherSuiteFilter cipherFilter, OpenSslApplicationProtocolNegotiator apn,
-- long sessionCacheSize, long sessionTimeout) throws SSLException {
+- public OpenSslClientContext(File trustCertCollectionFile, TrustManagerFactory trustManagerFactory,
+- File keyCertChainFile, File keyFile, String keyPassword,
+- KeyManagerFactory keyManagerFactory, Iterable<String> ciphers,
+- CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
+- long sessionCacheSize, long sessionTimeout)
+- throws SSLException {
- this(toX509CertificatesInternal(trustCertCollectionFile), trustManagerFactory,
- toX509CertificatesInternal(keyCertChainFile), toPrivateKeyInternal(keyFile, keyPassword),
-- keyPassword, keyManagerFactory, ciphers, cipherFilter,
-- apn, sessionCacheSize, sessionTimeout, ClientAuth.NONE, null, false, false);
-- }
--
-- OpenSslServerContext(
-- X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory,
-- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory,
-- Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
-- long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[] protocols, boolean startTls,
-- boolean enableOcsp) throws SSLException {
-- this(trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory, ciphers,
-- cipherFilter, toNegotiator(apn), sessionCacheSize, sessionTimeout, clientAuth, protocols, startTls,
-- enableOcsp);
+- keyPassword, keyManagerFactory, ciphers, cipherFilter, apn, null, sessionCacheSize,
+- sessionTimeout, false, KeyStore.getDefaultType());
- }
-
-- @SuppressWarnings("deprecation")
-- private OpenSslServerContext(
-- X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory,
-- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory,
-- Iterable<String> ciphers, CipherSuiteFilter cipherFilter, OpenSslApplicationProtocolNegotiator apn,
-- long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[] protocols, boolean startTls,
-- boolean enableOcsp) throws SSLException {
-- super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, SSL.SSL_MODE_SERVER, keyCertChain,
-- clientAuth, protocols, startTls, enableOcsp);
-- // Create a new SSL_CTX and configure it.
+- OpenSslClientContext(X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory,
+- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword,
+- KeyManagerFactory keyManagerFactory, Iterable<String> ciphers,
+- CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, String[] protocols,
+- long sessionCacheSize, long sessionTimeout, boolean enableOcsp, String keyStore)
+- throws SSLException {
+- super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, SSL.SSL_MODE_CLIENT, keyCertChain,
+- ClientAuth.NONE, protocols, false, enableOcsp);
- boolean success = false;
- try {
-- ServerContext context = newSessionContext(this, ctx, engineMap, trustCertCollection, trustManagerFactory,
-- keyCertChain, key, keyPassword, keyManagerFactory);
-- sessionContext = context.sessionContext;
-- keyMaterialManager = context.keyMaterialManager;
+- OpenSslKeyMaterialProvider.validateKeyMaterialSupported(keyCertChain, key, keyPassword);
+- sessionContext = newSessionContext(this, ctx, engineMap, trustCertCollection, trustManagerFactory,
+- keyCertChain, key, keyPassword, keyManagerFactory, keyStore);
- success = true;
- } finally {
- if (!success) {
@@ -1660,21 +1800,16 @@ index f57434b..0000000
- }
-
- @Override
-- public OpenSslServerSessionContext sessionContext() {
+- public OpenSslSessionContext sessionContext() {
- return sessionContext;
- }
--
-- @Override
-- OpenSslKeyMaterialManager keyMaterialManager() {
-- return keyMaterialManager;
-- }
-}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerSessionContext.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslServerSessionContext.java
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslContext.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslContext.java
deleted file mode 100644
-index 8c92deb..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerSessionContext.java
+index f18c0643fc..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslContext.java
+++ /dev/null
-@@ -1,124 +0,0 @@
+@@ -1,58 +0,0 @@
-/*
- * Copyright 2014 The Netty Project
- *
@@ -1692,119 +1827,53 @@ index 8c92deb..0000000
- */
-package io.netty.handler.ssl;
-
--import io.netty.internal.tcnative.SSL;
--import io.netty.internal.tcnative.SSLContext;
+-import io.netty.buffer.ByteBufAllocator;
-
--import java.util.concurrent.locks.Lock;
+-import java.security.cert.Certificate;
-
+-import javax.net.ssl.SSLEngine;
+-import javax.net.ssl.SSLException;
-
-/**
-- * {@link OpenSslSessionContext} implementation which offers extra methods which are only useful for the server-side.
+- * This class will use a finalizer to ensure native resources are automatically cleaned up. To avoid finalizers
+- * and manually release the native memory see {@link ReferenceCountedOpenSslContext}.
- */
--public final class OpenSslServerSessionContext extends OpenSslSessionContext {
-- OpenSslServerSessionContext(ReferenceCountedOpenSslContext context) {
-- super(context);
-- }
--
-- @Override
-- public void setSessionTimeout(int seconds) {
-- if (seconds < 0) {
-- throw new IllegalArgumentException();
-- }
-- Lock writerLock = context.ctxLock.writeLock();
-- writerLock.lock();
-- try {
-- SSLContext.setSessionCacheTimeout(context.ctx, seconds);
-- } finally {
-- writerLock.unlock();
-- }
-- }
--
-- @Override
-- public int getSessionTimeout() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
-- try {
-- return (int) SSLContext.getSessionCacheTimeout(context.ctx);
-- } finally {
-- readerLock.unlock();
-- }
-- }
--
-- @Override
-- public void setSessionCacheSize(int size) {
-- if (size < 0) {
-- throw new IllegalArgumentException();
-- }
-- Lock writerLock = context.ctxLock.writeLock();
-- writerLock.lock();
-- try {
-- SSLContext.setSessionCacheSize(context.ctx, size);
-- } finally {
-- writerLock.unlock();
-- }
+-public abstract class OpenSslContext extends ReferenceCountedOpenSslContext {
+- OpenSslContext(Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apnCfg,
+- long sessionCacheSize, long sessionTimeout, int mode, Certificate[] keyCertChain,
+- ClientAuth clientAuth, String[] protocols, boolean startTls, boolean enableOcsp)
+- throws SSLException {
+- super(ciphers, cipherFilter, apnCfg, sessionCacheSize, sessionTimeout, mode, keyCertChain,
+- clientAuth, protocols, startTls, enableOcsp, false);
- }
-
-- @Override
-- public int getSessionCacheSize() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
-- try {
-- return (int) SSLContext.getSessionCacheSize(context.ctx);
-- } finally {
-- readerLock.unlock();
-- }
+- OpenSslContext(Iterable<String> ciphers, CipherSuiteFilter cipherFilter,
+- OpenSslApplicationProtocolNegotiator apn, long sessionCacheSize,
+- long sessionTimeout, int mode, Certificate[] keyCertChain,
+- ClientAuth clientAuth, String[] protocols, boolean startTls,
+- boolean enableOcsp) throws SSLException {
+- super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, mode, keyCertChain, clientAuth, protocols,
+- startTls, enableOcsp, false);
- }
-
- @Override
-- public void setSessionCacheEnabled(boolean enabled) {
-- long mode = enabled ? SSL.SSL_SESS_CACHE_SERVER : SSL.SSL_SESS_CACHE_OFF;
--
-- Lock writerLock = context.ctxLock.writeLock();
-- writerLock.lock();
-- try {
-- SSLContext.setSessionCacheMode(context.ctx, mode);
-- } finally {
-- writerLock.unlock();
-- }
+- final SSLEngine newEngine0(ByteBufAllocator alloc, String peerHost, int peerPort, boolean jdkCompatibilityMode) {
+- return new OpenSslEngine(this, alloc, peerHost, peerPort, jdkCompatibilityMode);
- }
-
- @Override
-- public boolean isSessionCacheEnabled() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
-- try {
-- return SSLContext.getSessionCacheMode(context.ctx) == SSL.SSL_SESS_CACHE_SERVER;
-- } finally {
-- readerLock.unlock();
-- }
-- }
--
-- /**
-- * Set the context within which session be reused (server side only)
-- * See <a href="http://www.openssl.org/docs/ssl/SSL_CTX_set_session_id_context.html">
-- * man SSL_CTX_set_session_id_context</a>
-- *
-- * @param sidCtx can be any kind of binary data, it is therefore possible to use e.g. the name
-- * of the application and/or the hostname and/or service name
-- * @return {@code true} if success, {@code false} otherwise.
-- */
-- public boolean setSessionIdContext(byte[] sidCtx) {
-- Lock writerLock = context.ctxLock.writeLock();
-- writerLock.lock();
-- try {
-- return SSLContext.setSessionIdContext(context.ctx, sidCtx);
-- } finally {
-- writerLock.unlock();
-- }
+- @SuppressWarnings("FinalizeDeclaration")
+- protected final void finalize() throws Throwable {
+- super.finalize();
+- OpenSsl.releaseIfNeeded(this);
- }
-}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionContext.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionContext.java
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslEngine.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslEngine.java
deleted file mode 100644
-index 846a968..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionContext.java
+index a700dabf39..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslEngine.java
+++ /dev/null
-@@ -1,137 +0,0 @@
+@@ -1,41 +0,0 @@
-/*
- * Copyright 2014 The Netty Project
- *
@@ -1822,132 +1891,36 @@ index 846a968..0000000
- */
-package io.netty.handler.ssl;
-
--import io.netty.util.internal.ObjectUtil;
--import io.netty.internal.tcnative.SSL;
--import io.netty.internal.tcnative.SSLContext;
--import io.netty.internal.tcnative.SessionTicketKey;
+-import io.netty.buffer.ByteBufAllocator;
-
--import javax.net.ssl.SSLSession;
--import javax.net.ssl.SSLSessionContext;
--import java.util.Arrays;
--import java.util.Enumeration;
--import java.util.NoSuchElementException;
--import java.util.concurrent.locks.Lock;
+-import javax.net.ssl.SSLEngine;
-
-/**
-- * OpenSSL specific {@link SSLSessionContext} implementation.
+- * Implements a {@link SSLEngine} using
+- * <a href="https://www.openssl.org/docs/crypto/BIO_s_bio.html#EXAMPLE">OpenSSL BIO abstractions</a>.
+- * <p>
+- * This class will use a finalizer to ensure native resources are automatically cleaned up. To avoid finalizers
+- * and manually release the native memory see {@link ReferenceCountedOpenSslEngine}.
- */
--public abstract class OpenSslSessionContext implements SSLSessionContext {
-- private static final Enumeration<byte[]> EMPTY = new EmptyEnumeration();
--
-- private final OpenSslSessionStats stats;
-- final ReferenceCountedOpenSslContext context;
--
-- // IMPORTANT: We take the OpenSslContext and not just the long (which points the native instance) to prevent
-- // the GC to collect OpenSslContext as this would also free the pointer and so could result in a
-- // segfault when the user calls any of the methods here that try to pass the pointer down to the native
-- // level.
-- OpenSslSessionContext(ReferenceCountedOpenSslContext context) {
-- this.context = context;
-- stats = new OpenSslSessionStats(context);
-- }
--
-- @Override
-- public SSLSession getSession(byte[] bytes) {
-- if (bytes == null) {
-- throw new NullPointerException("bytes");
-- }
-- return null;
+-public final class OpenSslEngine extends ReferenceCountedOpenSslEngine {
+- OpenSslEngine(OpenSslContext context, ByteBufAllocator alloc, String peerHost, int peerPort,
+- boolean jdkCompatibilityMode) {
+- super(context, alloc, peerHost, peerPort, jdkCompatibilityMode, false);
- }
-
- @Override
-- public Enumeration<byte[]> getIds() {
-- return EMPTY;
-- }
--
-- /**
-- * Sets the SSL session ticket keys of this context.
-- * @deprecated use {@link #setTicketKeys(OpenSslSessionTicketKey...)}.
-- */
-- @Deprecated
-- public void setTicketKeys(byte[] keys) {
-- if (keys.length % SessionTicketKey.TICKET_KEY_SIZE != 0) {
-- throw new IllegalArgumentException("keys.length % " + SessionTicketKey.TICKET_KEY_SIZE + " != 0");
-- }
-- SessionTicketKey[] tickets = new SessionTicketKey[keys.length / SessionTicketKey.TICKET_KEY_SIZE];
-- for (int i = 0, a = 0; i < tickets.length; i++) {
-- byte[] name = Arrays.copyOfRange(keys, a, SessionTicketKey.NAME_SIZE);
-- a += SessionTicketKey.NAME_SIZE;
-- byte[] hmacKey = Arrays.copyOfRange(keys, a, SessionTicketKey.HMAC_KEY_SIZE);
-- i += SessionTicketKey.HMAC_KEY_SIZE;
-- byte[] aesKey = Arrays.copyOfRange(keys, a, SessionTicketKey.AES_KEY_SIZE);
-- a += SessionTicketKey.AES_KEY_SIZE;
-- tickets[i] = new SessionTicketKey(name, hmacKey, aesKey);
-- }
-- Lock writerLock = context.ctxLock.writeLock();
-- writerLock.lock();
-- try {
-- SSLContext.clearOptions(context.ctx, SSL.SSL_OP_NO_TICKET);
-- SSLContext.setSessionTicketKeys(context.ctx, tickets);
-- } finally {
-- writerLock.unlock();
-- }
-- }
--
-- /**
-- * Sets the SSL session ticket keys of this context.
-- */
-- public void setTicketKeys(OpenSslSessionTicketKey... keys) {
-- ObjectUtil.checkNotNull(keys, "keys");
-- SessionTicketKey[] ticketKeys = new SessionTicketKey[keys.length];
-- for (int i = 0; i < ticketKeys.length; i++) {
-- ticketKeys[i] = keys[i].key;
-- }
-- Lock writerLock = context.ctxLock.writeLock();
-- writerLock.lock();
-- try {
-- SSLContext.clearOptions(context.ctx, SSL.SSL_OP_NO_TICKET);
-- SSLContext.setSessionTicketKeys(context.ctx, ticketKeys);
-- } finally {
-- writerLock.unlock();
-- }
-- }
--
-- /**
-- * Enable or disable caching of SSL sessions.
-- */
-- public abstract void setSessionCacheEnabled(boolean enabled);
--
-- /**
-- * Return {@code true} if caching of SSL sessions is enabled, {@code false} otherwise.
-- */
-- public abstract boolean isSessionCacheEnabled();
--
-- /**
-- * Returns the stats of this context.
-- */
-- public OpenSslSessionStats stats() {
-- return stats;
-- }
--
-- private static final class EmptyEnumeration implements Enumeration<byte[]> {
-- @Override
-- public boolean hasMoreElements() {
-- return false;
-- }
--
-- @Override
-- public byte[] nextElement() {
-- throw new NoSuchElementException();
-- }
+- @SuppressWarnings("FinalizeDeclaration")
+- protected void finalize() throws Throwable {
+- super.finalize();
+- OpenSsl.releaseIfNeeded(this);
- }
-}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionStats.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionStats.java
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslEngineMap.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslEngineMap.java
deleted file mode 100644
-index f49b95f..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionStats.java
+index 02131b4b26..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslEngineMap.java
+++ /dev/null
-@@ -1,253 +0,0 @@
+@@ -1,35 +0,0 @@
-/*
- * Copyright 2014 The Netty Project
- *
@@ -1963,252 +1936,524 @@ index f49b95f..0000000
- * License for the specific language governing permissions and limitations
- * under the License.
- */
--
-package io.netty.handler.ssl;
-
--import io.netty.internal.tcnative.SSLContext;
+-interface OpenSslEngineMap {
-
--import java.util.concurrent.locks.Lock;
+- /**
+- * Remove the {@link OpenSslEngine} with the given {@code ssl} address and
+- * return it.
+- */
+- ReferenceCountedOpenSslEngine remove(long ssl);
-
--/**
-- * Stats exposed by an OpenSSL session context.
+- /**
+- * Add a {@link OpenSslEngine} to this {@link OpenSslEngineMap}.
+- */
+- void add(ReferenceCountedOpenSslEngine engine);
+-
+- /**
+- * Get the {@link OpenSslEngine} for the given {@code ssl} address.
+- */
+- ReferenceCountedOpenSslEngine get(long ssl);
+-}
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialManager.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialManager.java
+deleted file mode 100644
+index 7acbf70cfe..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialManager.java
++++ /dev/null
+@@ -1,127 +0,0 @@
+-/*
+- * Copyright 2016 The Netty Project
- *
-- * @see <a href="https://www.openssl.org/docs/manmaster/man3/SSL_CTX_sess_number.html">SSL_CTX_sess_number</a>
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- * http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
- */
--public final class OpenSslSessionStats {
+-package io.netty.handler.ssl;
-
-- private final ReferenceCountedOpenSslContext context;
+-import javax.net.ssl.SSLException;
+-import javax.net.ssl.X509ExtendedKeyManager;
+-import javax.net.ssl.X509KeyManager;
+-import javax.security.auth.x500.X500Principal;
+-import java.security.PrivateKey;
+-import java.security.cert.X509Certificate;
+-import java.util.HashMap;
+-import java.util.HashSet;
+-import java.util.Map;
+-import java.util.Set;
-
-- // IMPORTANT: We take the OpenSslContext and not just the long (which points the native instance) to prevent
-- // the GC to collect OpenSslContext as this would also free the pointer and so could result in a
-- // segfault when the user calls any of the methods here that try to pass the pointer down to the native
-- // level.
-- OpenSslSessionStats(ReferenceCountedOpenSslContext context) {
-- this.context = context;
+-
+-/**
+- * Manages key material for {@link OpenSslEngine}s and so set the right {@link PrivateKey}s and
+- * {@link X509Certificate}s.
+- */
+-final class OpenSslKeyMaterialManager {
+-
+- // Code in this class is inspired by code of conscrypts:
+- // - https://android.googlesource.com/platform/external/
+- // conscrypt/+/master/src/main/java/org/conscrypt/OpenSSLEngineImpl.java
+- // - https://android.googlesource.com/platform/external/
+- // conscrypt/+/master/src/main/java/org/conscrypt/SSLParametersImpl.java
+- //
+- static final String KEY_TYPE_RSA = "RSA";
+- static final String KEY_TYPE_DH_RSA = "DH_RSA";
+- static final String KEY_TYPE_EC = "EC";
+- static final String KEY_TYPE_EC_EC = "EC_EC";
+- static final String KEY_TYPE_EC_RSA = "EC_RSA";
+-
+- // key type mappings for types.
+- private static final Map<String, String> KEY_TYPES = new HashMap<String, String>();
+- static {
+- KEY_TYPES.put("RSA", KEY_TYPE_RSA);
+- KEY_TYPES.put("DHE_RSA", KEY_TYPE_RSA);
+- KEY_TYPES.put("ECDHE_RSA", KEY_TYPE_RSA);
+- KEY_TYPES.put("ECDHE_ECDSA", KEY_TYPE_EC);
+- KEY_TYPES.put("ECDH_RSA", KEY_TYPE_EC_RSA);
+- KEY_TYPES.put("ECDH_ECDSA", KEY_TYPE_EC_EC);
+- KEY_TYPES.put("DH_RSA", KEY_TYPE_DH_RSA);
- }
-
-- /**
-- * Returns the current number of sessions in the internal session cache.
-- */
-- public long number() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
-- try {
-- return SSLContext.sessionNumber(context.ctx);
-- } finally {
-- readerLock.unlock();
-- }
+- private final OpenSslKeyMaterialProvider provider;
+-
+- OpenSslKeyMaterialManager(OpenSslKeyMaterialProvider provider) {
+- this.provider = provider;
- }
-
-- /**
-- * Returns the number of started SSL/TLS handshakes in client mode.
-- */
-- public long connect() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
-- try {
-- return SSLContext.sessionConnect(context.ctx);
-- } finally {
-- readerLock.unlock();
+- void setKeyMaterialServerSide(ReferenceCountedOpenSslEngine engine) throws SSLException {
+- String[] authMethods = engine.authMethods();
+- if (authMethods.length == 0) {
+- return;
+- }
+- Set<String> aliases = new HashSet<String>(authMethods.length);
+- for (String authMethod : authMethods) {
+- String type = KEY_TYPES.get(authMethod);
+- if (type != null) {
+- String alias = chooseServerAlias(engine, type);
+- if (alias != null && aliases.add(alias)) {
+- if (!setKeyMaterial(engine, alias)) {
+- return;
+- }
+- }
+- }
- }
- }
-
-- /**
-- * Returns the number of successfully established SSL/TLS sessions in client mode.
-- */
-- public long connectGood() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
-- try {
-- return SSLContext.sessionConnectGood(context.ctx);
-- } finally {
-- readerLock.unlock();
+- void setKeyMaterialClientSide(ReferenceCountedOpenSslEngine engine, String[] keyTypes,
+- X500Principal[] issuer) throws SSLException {
+- String alias = chooseClientAlias(engine, keyTypes, issuer);
+- // Only try to set the keymaterial if we have a match. This is also consistent with what OpenJDK does:
+- // http://hg.openjdk.java.net/jdk/jdk11/file/76072a077ee1/
+- // src/java.base/share/classes/sun/security/ssl/CertificateRequest.java#l362
+- if (alias != null) {
+- setKeyMaterial(engine, alias);
- }
- }
-
-- /**
-- * Returns the number of start renegotiations in client mode.
-- */
-- public long connectRenegotiate() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
+- private boolean setKeyMaterial(ReferenceCountedOpenSslEngine engine, String alias) throws SSLException {
+- OpenSslKeyMaterial keyMaterial = null;
- try {
-- return SSLContext.sessionConnectRenegotiate(context.ctx);
+- keyMaterial = provider.chooseKeyMaterial(engine.alloc, alias);
+- return keyMaterial == null || engine.setKeyMaterial(keyMaterial);
+- } catch (SSLException e) {
+- throw e;
+- } catch (Exception e) {
+- throw new SSLException(e);
- } finally {
-- readerLock.unlock();
+- if (keyMaterial != null) {
+- keyMaterial.release();
+- }
+- }
+- }
+- private String chooseClientAlias(ReferenceCountedOpenSslEngine engine,
+- String[] keyTypes, X500Principal[] issuer) {
+- X509KeyManager manager = provider.keyManager();
+- if (manager instanceof X509ExtendedKeyManager) {
+- return ((X509ExtendedKeyManager) manager).chooseEngineClientAlias(keyTypes, issuer, engine);
- }
+- return manager.chooseClientAlias(keyTypes, issuer, null);
- }
-
-- /**
-- * Returns the number of started SSL/TLS handshakes in server mode.
-- */
-- public long accept() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
-- try {
-- return SSLContext.sessionAccept(context.ctx);
-- } finally {
-- readerLock.unlock();
+- private String chooseServerAlias(ReferenceCountedOpenSslEngine engine, String type) {
+- X509KeyManager manager = provider.keyManager();
+- if (manager instanceof X509ExtendedKeyManager) {
+- return ((X509ExtendedKeyManager) manager).chooseEngineServerAlias(type, null, engine);
- }
+- return manager.chooseServerAlias(type, null, null);
- }
+-}
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialProvider.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialProvider.java
+deleted file mode 100644
+index f931fcfdbb..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslKeyMaterialProvider.java
++++ /dev/null
+@@ -1,154 +0,0 @@
+-/*
+- * Copyright 2018 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- * http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-package io.netty.handler.ssl;
+-
+-import io.netty.buffer.ByteBufAllocator;
+-import io.netty.buffer.UnpooledByteBufAllocator;
+-import io.netty.internal.tcnative.SSL;
+-
+-import javax.net.ssl.SSLException;
+-import javax.net.ssl.X509KeyManager;
+-import java.security.PrivateKey;
+-import java.security.cert.X509Certificate;
+-
+-import static io.netty.handler.ssl.ReferenceCountedOpenSslContext.toBIO;
+-
+-/**
+- * Provides {@link OpenSslKeyMaterial} for a given alias.
+- */
+-class OpenSslKeyMaterialProvider {
+-
+- private final X509KeyManager keyManager;
+- private final String password;
+-
+- OpenSslKeyMaterialProvider(X509KeyManager keyManager, String password) {
+- this.keyManager = keyManager;
+- this.password = password;
+- }
+-
+- static void validateKeyMaterialSupported(X509Certificate[] keyCertChain, PrivateKey key, String keyPassword)
+- throws SSLException {
+- validateSupported(keyCertChain);
+- validateSupported(key, keyPassword);
+- }
+-
+- private static void validateSupported(PrivateKey key, String password) throws SSLException {
+- if (key == null) {
+- return;
+- }
+-
+- long pkeyBio = 0;
+- long pkey = 0;
-
-- /**
-- * Returns the number of successfully established SSL/TLS sessions in server mode.
-- */
-- public long acceptGood() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
- try {
-- return SSLContext.sessionAcceptGood(context.ctx);
+- pkeyBio = toBIO(UnpooledByteBufAllocator.DEFAULT, key);
+- pkey = SSL.parsePrivateKey(pkeyBio, password);
+- } catch (Exception e) {
+- throw new SSLException("PrivateKey type not supported " + key.getFormat(), e);
- } finally {
-- readerLock.unlock();
+- SSL.freeBIO(pkeyBio);
+- if (pkey != 0) {
+- SSL.freePrivateKey(pkey);
+- }
- }
- }
-
-- /**
-- * Returns the number of start renegotiations in server mode.
-- */
-- public long acceptRenegotiate() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
+- private static void validateSupported(X509Certificate[] certificates) throws SSLException {
+- if (certificates == null || certificates.length == 0) {
+- return;
+- }
+-
+- long chainBio = 0;
+- long chain = 0;
+- PemEncoded encoded = null;
- try {
-- return SSLContext.sessionAcceptRenegotiate(context.ctx);
+- encoded = PemX509Certificate.toPEM(UnpooledByteBufAllocator.DEFAULT, true, certificates);
+- chainBio = toBIO(UnpooledByteBufAllocator.DEFAULT, encoded.retain());
+- chain = SSL.parseX509Chain(chainBio);
+- } catch (Exception e) {
+- throw new SSLException("Certificate type not supported", e);
- } finally {
-- readerLock.unlock();
+- SSL.freeBIO(chainBio);
+- if (chain != 0) {
+- SSL.freeX509Chain(chain);
+- }
+- if (encoded != null) {
+- encoded.release();
+- }
- }
- }
-
- /**
-- * Returns the number of successfully reused sessions. In client mode, a session set with {@code SSL_set_session}
-- * successfully reused is counted as a hit. In server mode, a session successfully retrieved from internal or
-- * external cache is counted as a hit.
+- * Returns the underlying {@link X509KeyManager} that is used.
- */
-- public long hits() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
-- try {
-- return SSLContext.sessionHits(context.ctx);
-- } finally {
-- readerLock.unlock();
-- }
+- X509KeyManager keyManager() {
+- return keyManager;
- }
-
- /**
-- * Returns the number of successfully retrieved sessions from the external session cache in server mode.
+- * Returns the {@link OpenSslKeyMaterial} or {@code null} (if none) that should be used during the handshake by
+- * OpenSSL.
- */
-- public long cbHits() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
+- OpenSslKeyMaterial chooseKeyMaterial(ByteBufAllocator allocator, String alias) throws Exception {
+- X509Certificate[] certificates = keyManager.getCertificateChain(alias);
+- if (certificates == null || certificates.length == 0) {
+- return null;
+- }
+-
+- PrivateKey key = keyManager.getPrivateKey(alias);
+- PemEncoded encoded = PemX509Certificate.toPEM(allocator, true, certificates);
+- long chainBio = 0;
+- long pkeyBio = 0;
+- long chain = 0;
+- long pkey = 0;
- try {
-- return SSLContext.sessionCbHits(context.ctx);
+- chainBio = toBIO(allocator, encoded.retain());
+- chain = SSL.parseX509Chain(chainBio);
+-
+- OpenSslKeyMaterial keyMaterial;
+- if (key instanceof OpenSslPrivateKey) {
+- keyMaterial = ((OpenSslPrivateKey) key).newKeyMaterial(chain, certificates);
+- } else {
+- pkeyBio = toBIO(allocator, key);
+- pkey = key == null ? 0 : SSL.parsePrivateKey(pkeyBio, password);
+- keyMaterial = new DefaultOpenSslKeyMaterial(chain, pkey, certificates);
+- }
+-
+- // See the chain and pkey to 0 so we will not release it as the ownership was
+- // transferred to OpenSslKeyMaterial.
+- chain = 0;
+- pkey = 0;
+- return keyMaterial;
- } finally {
-- readerLock.unlock();
+- SSL.freeBIO(chainBio);
+- SSL.freeBIO(pkeyBio);
+- if (chain != 0) {
+- SSL.freeX509Chain(chain);
+- }
+- if (pkey != 0) {
+- SSL.freePrivateKey(pkey);
+- }
+- encoded.release();
- }
- }
-
- /**
-- * Returns the number of sessions proposed by clients that were not found in the internal session cache
-- * in server mode.
+- * Will be invoked once the provider should be destroyed.
- */
-- public long misses() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
-- try {
-- return SSLContext.sessionMisses(context.ctx);
-- } finally {
-- readerLock.unlock();
-- }
+- void destroy() {
+- // NOOP.
- }
+-}
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslPrivateKey.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslPrivateKey.java
+deleted file mode 100644
+index c2e4f108b7..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslPrivateKey.java
++++ /dev/null
+@@ -1,191 +0,0 @@
+-/*
+- * Copyright 2018 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- * http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-package io.netty.handler.ssl;
-
-- /**
-- * Returns the number of sessions proposed by clients and either found in the internal or external session cache
-- * in server mode, but that were invalid due to timeout. These sessions are not included in the {@link #hits()}
-- * count.
-- */
-- public long timeouts() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
-- try {
-- return SSLContext.sessionTimeouts(context.ctx);
-- } finally {
-- readerLock.unlock();
-- }
+-import io.netty.internal.tcnative.SSL;
+-import io.netty.util.AbstractReferenceCounted;
+-import io.netty.util.IllegalReferenceCountException;
+-import io.netty.util.internal.EmptyArrays;
+-
+-import javax.security.auth.Destroyable;
+-import java.security.PrivateKey;
+-import java.security.cert.X509Certificate;
+-
+-final class OpenSslPrivateKey extends AbstractReferenceCounted implements PrivateKey {
+-
+- private long privateKeyAddress;
+-
+- OpenSslPrivateKey(long privateKeyAddress) {
+- this.privateKeyAddress = privateKeyAddress;
- }
-
-- /**
-- * Returns the number of sessions that were removed because the maximum session cache size was exceeded.
-- */
-- public long cacheFull() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
-- try {
-- return SSLContext.sessionCacheFull(context.ctx);
-- } finally {
-- readerLock.unlock();
-- }
+- @Override
+- public String getAlgorithm() {
+- return "unknown";
- }
-
-- /**
-- * Returns the number of times a client presented a ticket that did not match any key in the list.
-- */
-- public long ticketKeyFail() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
-- try {
-- return SSLContext.sessionTicketKeyFail(context.ctx);
-- } finally {
-- readerLock.unlock();
+- @Override
+- public String getFormat() {
+- // As we do not support encoding we should return null as stated in the javadocs of PrivateKey.
+- return null;
+- }
+-
+- @Override
+- public byte[] getEncoded() {
+- return null;
+- }
+-
+- private long privateKeyAddress() {
+- if (refCnt() <= 0) {
+- throw new IllegalReferenceCountException();
- }
+- return privateKeyAddress;
+- }
+-
+- @Override
+- protected void deallocate() {
+- SSL.freePrivateKey(privateKeyAddress);
+- privateKeyAddress = 0;
+- }
+-
+- @Override
+- public OpenSslPrivateKey retain() {
+- super.retain();
+- return this;
+- }
+-
+- @Override
+- public OpenSslPrivateKey retain(int increment) {
+- super.retain(increment);
+- return this;
+- }
+-
+- @Override
+- public OpenSslPrivateKey touch() {
+- super.touch();
+- return this;
+- }
+-
+- @Override
+- public OpenSslPrivateKey touch(Object hint) {
+- return this;
- }
-
- /**
-- * Returns the number of times a client did not present a ticket and we issued a new one
+- * NOTE: This is a JDK8 interface/method. Due to backwards compatibility
+- * reasons it's not possible to slap the {@code @Override} annotation onto
+- * this method.
+- *
+- * @see Destroyable#destroy()
- */
-- public long ticketKeyNew() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
-- try {
-- return SSLContext.sessionTicketKeyNew(context.ctx);
-- } finally {
-- readerLock.unlock();
-- }
+- @Override
+- public void destroy() {
+- release(refCnt());
- }
-
- /**
-- * Returns the number of times a client presented a ticket derived from an older key,
-- * and we upgraded to the primary key.
+- * NOTE: This is a JDK8 interface/method. Due to backwards compatibility
+- * reasons it's not possible to slap the {@code @Override} annotation onto
+- * this method.
+- *
+- * @see Destroyable#isDestroyed()
- */
-- public long ticketKeyRenew() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
-- try {
-- return SSLContext.sessionTicketKeyRenew(context.ctx);
-- } finally {
-- readerLock.unlock();
-- }
+- @Override
+- public boolean isDestroyed() {
+- return refCnt() == 0;
- }
-
- /**
-- * Returns the number of times a client presented a ticket derived from the primary key.
+- * Create a new {@link OpenSslKeyMaterial} which uses the private key that is held by {@link OpenSslPrivateKey}.
+- *
+- * When the material is created we increment the reference count of the enclosing {@link OpenSslPrivateKey} and
+- * decrement it again when the reference count of the {@link OpenSslKeyMaterial} reaches {@code 0}.
- */
-- public long ticketKeyResume() {
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
-- try {
-- return SSLContext.sessionTicketKeyResume(context.ctx);
-- } finally {
-- readerLock.unlock();
+- OpenSslKeyMaterial newKeyMaterial(long certificateChain, X509Certificate[] chain) {
+- return new OpenSslPrivateKeyMaterial(certificateChain, chain);
+- }
+-
+- // Package-private for unit-test only
+- final class OpenSslPrivateKeyMaterial extends AbstractReferenceCounted implements OpenSslKeyMaterial {
+-
+- // Package-private for unit-test only
+- long certificateChain;
+- private final X509Certificate[] x509CertificateChain;
+-
+- OpenSslPrivateKeyMaterial(long certificateChain, X509Certificate[] x509CertificateChain) {
+- this.certificateChain = certificateChain;
+- this.x509CertificateChain = x509CertificateChain == null ?
+- EmptyArrays.EMPTY_X509_CERTIFICATES : x509CertificateChain;
+- OpenSslPrivateKey.this.retain();
+- }
+-
+- @Override
+- public X509Certificate[] certificateChain() {
+- return x509CertificateChain.clone();
+- }
+-
+- @Override
+- public long certificateChainAddress() {
+- if (refCnt() <= 0) {
+- throw new IllegalReferenceCountException();
+- }
+- return certificateChain;
+- }
+-
+- @Override
+- public long privateKeyAddress() {
+- if (refCnt() <= 0) {
+- throw new IllegalReferenceCountException();
+- }
+- return OpenSslPrivateKey.this.privateKeyAddress();
+- }
+-
+- @Override
+- public OpenSslKeyMaterial touch(Object hint) {
+- OpenSslPrivateKey.this.touch(hint);
+- return this;
+- }
+-
+- @Override
+- public OpenSslKeyMaterial retain() {
+- super.retain();
+- return this;
+- }
+-
+- @Override
+- public OpenSslKeyMaterial retain(int increment) {
+- super.retain(increment);
+- return this;
+- }
+-
+- @Override
+- public OpenSslKeyMaterial touch() {
+- OpenSslPrivateKey.this.touch();
+- return this;
+- }
+-
+- @Override
+- protected void deallocate() {
+- releaseChain();
+- OpenSslPrivateKey.this.release();
+- }
+-
+- private void releaseChain() {
+- SSL.freeX509Chain(certificateChain);
+- certificateChain = 0;
- }
- }
-}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionTicketKey.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionTicketKey.java
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslPrivateKeyMethod.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslPrivateKeyMethod.java
deleted file mode 100644
-index 79f71a6..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionTicketKey.java
+index d9fc877269..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslPrivateKeyMethod.java
+++ /dev/null
-@@ -1,78 +0,0 @@
+@@ -1,62 +0,0 @@
-/*
-- * Copyright 2015 The Netty Project
+- * Copyright 2019 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
@@ -2224,75 +2469,59 @@ index 79f71a6..0000000
- */
-package io.netty.handler.ssl;
-
--import io.netty.internal.tcnative.SessionTicketKey;
+-import io.netty.internal.tcnative.SSLPrivateKeyMethod;
+-import io.netty.util.internal.UnstableApi;
+-
+-import javax.net.ssl.SSLEngine;
-
-/**
-- * Session Ticket Key
+- * Allow to customize private key signing / decrypting (when using RSA). Only supported when using BoringSSL atm.
- */
--public final class OpenSslSessionTicketKey {
--
-- /**
-- * Size of session ticket key name
-- */
-- public static final int NAME_SIZE = SessionTicketKey.NAME_SIZE;
-- /**
-- * Size of session ticket key HMAC key
-- */
-- public static final int HMAC_KEY_SIZE = SessionTicketKey.HMAC_KEY_SIZE;
-- /**
-- * Size of session ticket key AES key
-- */
-- public static final int AES_KEY_SIZE = SessionTicketKey.AES_KEY_SIZE;
-- /**
-- * Size of session ticker key
-- */
-- public static final int TICKET_KEY_SIZE = SessionTicketKey.TICKET_KEY_SIZE;
--
-- final SessionTicketKey key;
+-@UnstableApi
+-public interface OpenSslPrivateKeyMethod {
+- int SSL_SIGN_RSA_PKCS1_SHA1 = SSLPrivateKeyMethod.SSL_SIGN_RSA_PKCS1_SHA1;
+- int SSL_SIGN_RSA_PKCS1_SHA256 = SSLPrivateKeyMethod.SSL_SIGN_RSA_PKCS1_SHA256;
+- int SSL_SIGN_RSA_PKCS1_SHA384 = SSLPrivateKeyMethod.SSL_SIGN_RSA_PKCS1_SHA384;
+- int SSL_SIGN_RSA_PKCS1_SHA512 = SSLPrivateKeyMethod.SSL_SIGN_RSA_PKCS1_SHA512;
+- int SSL_SIGN_ECDSA_SHA1 = SSLPrivateKeyMethod.SSL_SIGN_ECDSA_SHA1;
+- int SSL_SIGN_ECDSA_SECP256R1_SHA256 = SSLPrivateKeyMethod.SSL_SIGN_ECDSA_SECP256R1_SHA256;
+- int SSL_SIGN_ECDSA_SECP384R1_SHA384 = SSLPrivateKeyMethod.SSL_SIGN_ECDSA_SECP384R1_SHA384;
+- int SSL_SIGN_ECDSA_SECP521R1_SHA512 = SSLPrivateKeyMethod.SSL_SIGN_ECDSA_SECP521R1_SHA512;
+- int SSL_SIGN_RSA_PSS_RSAE_SHA256 = SSLPrivateKeyMethod.SSL_SIGN_RSA_PSS_RSAE_SHA256;
+- int SSL_SIGN_RSA_PSS_RSAE_SHA384 = SSLPrivateKeyMethod.SSL_SIGN_RSA_PSS_RSAE_SHA384;
+- int SSL_SIGN_RSA_PSS_RSAE_SHA512 = SSLPrivateKeyMethod.SSL_SIGN_RSA_PSS_RSAE_SHA512;
+- int SSL_SIGN_ED25519 = SSLPrivateKeyMethod.SSL_SIGN_ED25519;
+- int SSL_SIGN_RSA_PKCS1_MD5_SHA1 = SSLPrivateKeyMethod.SSL_SIGN_RSA_PKCS1_MD5_SHA1;
-
- /**
-- * Construct a OpenSslSessionTicketKey.
+- * Signs the input with the given key and returns the signed bytes.
- *
-- * @param name the name of the session ticket key
-- * @param hmacKey the HMAC key of the session ticket key
-- * @param aesKey the AES key of the session ticket key
+- * @param engine the {@link SSLEngine}
+- * @param signatureAlgorithm the algorithm to use for signing
+- * @param input the digest itself
+- * @return the signed data (must not be {@code null})
+- * @throws Exception thrown if an error is encountered during the signing
- */
-- public OpenSslSessionTicketKey(byte[] name, byte[] hmacKey, byte[] aesKey) {
-- key = new SessionTicketKey(name.clone(), hmacKey.clone(), aesKey.clone());
-- }
--
-- /**
-- * Get name.
-- * @return the name of the session ticket key
-- */
-- public byte[] name() {
-- return key.getName().clone();
-- }
--
-- /**
-- * Get HMAC key.
-- * @return the HMAC key of the session ticket key
-- */
-- public byte[] hmacKey() {
-- return key.getHmacKey().clone();
-- }
+- byte[] sign(SSLEngine engine, int signatureAlgorithm, byte[] input) throws Exception;
-
- /**
-- * Get AES Key.
-- * @return the AES key of the session ticket key
+- * Decrypts the input with the given key and returns the decrypted bytes.
+- *
+- * @param engine the {@link SSLEngine}
+- * @param input the input which should be decrypted
+- * @return the decrypted data (must not be {@code null})
+- * @throws Exception thrown if an error is encountered during the decrypting
- */
-- public byte[] aesKey() {
-- return key.getAesKey().clone();
-- }
+- byte[] decrypt(SSLEngine engine, byte[] input) throws Exception;
-}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslClientContext.java b/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslClientContext.java
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerContext.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslServerContext.java
deleted file mode 100644
-index b213573..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslClientContext.java
+index da342de0f2..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerContext.java
+++ /dev/null
-@@ -1,298 +0,0 @@
+@@ -1,367 +0,0 @@
-/*
-- * Copyright 2016 The Netty Project
+- * Copyright 2014 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
@@ -2308,295 +2537,364 @@ index b213573..0000000
- */
-package io.netty.handler.ssl;
-
--import io.netty.util.internal.logging.InternalLogger;
--import io.netty.util.internal.logging.InternalLoggerFactory;
--import io.netty.internal.tcnative.CertificateRequestedCallback;
-import io.netty.internal.tcnative.SSL;
--import io.netty.internal.tcnative.SSLContext;
-
+-import java.io.File;
-import java.security.KeyStore;
-import java.security.PrivateKey;
-import java.security.cert.X509Certificate;
--import java.util.HashSet;
--import java.util.Set;
-
+-import javax.net.ssl.KeyManager;
-import javax.net.ssl.KeyManagerFactory;
-import javax.net.ssl.SSLException;
--import javax.net.ssl.SSLHandshakeException;
+-import javax.net.ssl.TrustManager;
-import javax.net.ssl.TrustManagerFactory;
--import javax.net.ssl.X509ExtendedKeyManager;
--import javax.net.ssl.X509ExtendedTrustManager;
--import javax.net.ssl.X509KeyManager;
--import javax.net.ssl.X509TrustManager;
--import javax.security.auth.x500.X500Principal;
+-
+-import static io.netty.handler.ssl.ReferenceCountedOpenSslServerContext.newSessionContext;
-
-/**
-- * A client-side {@link SslContext} which uses OpenSSL's SSL/TLS implementation.
-- * <p>Instances of this class must be {@link #release() released} or else native memory will leak!
-- *
-- * <p>Instances of this class <strong>must not</strong> be released before any {@link ReferenceCountedOpenSslEngine}
-- * which depends upon the instance of this class is released. Otherwise if any method of
-- * {@link ReferenceCountedOpenSslEngine} is called which uses this class's JNI resources the JVM may crash.
+- * A server-side {@link SslContext} which uses OpenSSL's SSL/TLS implementation.
+- * <p>This class will use a finalizer to ensure native resources are automatically cleaned up. To avoid finalizers
+- * and manually release the native memory see {@link ReferenceCountedOpenSslServerContext}.
- */
--public final class ReferenceCountedOpenSslClientContext extends ReferenceCountedOpenSslContext {
-- private static final InternalLogger logger =
-- InternalLoggerFactory.getInstance(ReferenceCountedOpenSslClientContext.class);
-- private final OpenSslSessionContext sessionContext;
+-public final class OpenSslServerContext extends OpenSslContext {
+- private final OpenSslServerSessionContext sessionContext;
-
-- ReferenceCountedOpenSslClientContext(X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory,
-- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword,
-- KeyManagerFactory keyManagerFactory, Iterable<String> ciphers,
-- CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
-- String[] protocols, long sessionCacheSize, long sessionTimeout,
-- boolean enableOcsp) throws SSLException {
-- super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, SSL.SSL_MODE_CLIENT, keyCertChain,
-- ClientAuth.NONE, protocols, false, enableOcsp, true);
-- boolean success = false;
-- try {
-- sessionContext = newSessionContext(this, ctx, engineMap, trustCertCollection, trustManagerFactory,
-- keyCertChain, key, keyPassword, keyManagerFactory);
-- success = true;
-- } finally {
-- if (!success) {
-- release();
-- }
-- }
+- /**
+- * Creates a new instance.
+- *
+- * @param certChainFile an X.509 certificate chain file in PEM format
+- * @param keyFile a PKCS#8 private key file in PEM format
+- * @deprecated use {@link SslContextBuilder}
+- */
+- @Deprecated
+- public OpenSslServerContext(File certChainFile, File keyFile) throws SSLException {
+- this(certChainFile, keyFile, null);
- }
-
-- @Override
-- OpenSslKeyMaterialManager keyMaterialManager() {
-- return null;
+- /**
+- * Creates a new instance.
+- *
+- * @param certChainFile an X.509 certificate chain file in PEM format
+- * @param keyFile a PKCS#8 private key file in PEM format
+- * @param keyPassword the password of the {@code keyFile}.
+- * {@code null} if it's not password-protected.
+- * @deprecated use {@link SslContextBuilder}
+- */
+- @Deprecated
+- public OpenSslServerContext(File certChainFile, File keyFile, String keyPassword) throws SSLException {
+- this(certChainFile, keyFile, keyPassword, null, IdentityCipherSuiteFilter.INSTANCE,
+- ApplicationProtocolConfig.DISABLED, 0, 0);
- }
-
-- @Override
-- public OpenSslSessionContext sessionContext() {
-- return sessionContext;
+- /**
+- * Creates a new instance.
+- *
+- * @param certChainFile an X.509 certificate chain file in PEM format
+- * @param keyFile a PKCS#8 private key file in PEM format
+- * @param keyPassword the password of the {@code keyFile}.
+- * {@code null} if it's not password-protected.
+- * @param ciphers the cipher suites to enable, in the order of preference.
+- * {@code null} to use the default cipher suites.
+- * @param apn Provides a means to configure parameters related to application protocol negotiation.
+- * @param sessionCacheSize the size of the cache used for storing SSL session objects.
+- * {@code 0} to use the default value.
+- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
+- * {@code 0} to use the default value.
+- * @deprecated use {@link SslContextBuilder}
+- */
+- @Deprecated
+- public OpenSslServerContext(
+- File certChainFile, File keyFile, String keyPassword,
+- Iterable<String> ciphers, ApplicationProtocolConfig apn,
+- long sessionCacheSize, long sessionTimeout) throws SSLException {
+- this(certChainFile, keyFile, keyPassword, ciphers, IdentityCipherSuiteFilter.INSTANCE,
+- apn, sessionCacheSize, sessionTimeout);
- }
-
-- static OpenSslSessionContext newSessionContext(ReferenceCountedOpenSslContext thiz, long ctx,
-- OpenSslEngineMap engineMap,
-- X509Certificate[] trustCertCollection,
-- TrustManagerFactory trustManagerFactory,
-- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword,
-- KeyManagerFactory keyManagerFactory) throws SSLException {
-- if (key == null && keyCertChain != null || key != null && keyCertChain == null) {
-- throw new IllegalArgumentException(
-- "Either both keyCertChain and key needs to be null or none of them");
-- }
-- try {
-- if (!OpenSsl.useKeyManagerFactory()) {
-- if (keyManagerFactory != null) {
-- throw new IllegalArgumentException(
-- "KeyManagerFactory not supported");
-- }
-- if (keyCertChain != null/* && key != null*/) {
-- setKeyMaterial(ctx, keyCertChain, key, keyPassword);
-- }
-- } else {
-- // javadocs state that keyManagerFactory has precedent over keyCertChain
-- if (keyManagerFactory == null && keyCertChain != null) {
-- keyManagerFactory = buildKeyManagerFactory(
-- keyCertChain, key, keyPassword, keyManagerFactory);
-- }
--
-- if (keyManagerFactory != null) {
-- X509KeyManager keyManager = chooseX509KeyManager(keyManagerFactory.getKeyManagers());
-- OpenSslKeyMaterialManager materialManager = useExtendedKeyManager(keyManager) ?
-- new OpenSslExtendedKeyMaterialManager(
-- (X509ExtendedKeyManager) keyManager, keyPassword) :
-- new OpenSslKeyMaterialManager(keyManager, keyPassword);
-- SSLContext.setCertRequestedCallback(ctx, new OpenSslCertificateRequestedCallback(
-- engineMap, materialManager));
-- }
-- }
-- } catch (Exception e) {
-- throw new SSLException("failed to set certificate and key", e);
-- }
--
-- SSLContext.setVerify(ctx, SSL.SSL_CVERIFY_NONE, VERIFY_DEPTH);
--
-- try {
-- if (trustCertCollection != null) {
-- trustManagerFactory = buildTrustManagerFactory(trustCertCollection, trustManagerFactory);
-- } else if (trustManagerFactory == null) {
-- trustManagerFactory = TrustManagerFactory.getInstance(
-- TrustManagerFactory.getDefaultAlgorithm());
-- trustManagerFactory.init((KeyStore) null);
-- }
-- final X509TrustManager manager = chooseTrustManager(trustManagerFactory.getTrustManagers());
--
-- // IMPORTANT: The callbacks set for verification must be static to prevent memory leak as
-- // otherwise the context can never be collected. This is because the JNI code holds
-- // a global reference to the callbacks.
-- //
-- // See https://github.com/netty/netty/issues/5372
--
-- // Use this to prevent an error when running on java < 7
-- if (useExtendedTrustManager(manager)) {
-- SSLContext.setCertVerifyCallback(ctx,
-- new ExtendedTrustManagerVerifyCallback(engineMap, (X509ExtendedTrustManager) manager));
-- } else {
-- SSLContext.setCertVerifyCallback(ctx, new TrustManagerVerifyCallback(engineMap, manager));
-- }
-- } catch (Exception e) {
-- throw new SSLException("unable to setup trustmanager", e);
-- }
-- return new OpenSslClientSessionContext(thiz);
+- /**
+- * Creates a new instance.
+- *
+- * @param certChainFile an X.509 certificate chain file in PEM format
+- * @param keyFile a PKCS#8 private key file in PEM format
+- * @param keyPassword the password of the {@code keyFile}.
+- * {@code null} if it's not password-protected.
+- * @param ciphers the cipher suites to enable, in the order of preference.
+- * {@code null} to use the default cipher suites.
+- * @param nextProtocols the application layer protocols to accept, in the order of preference.
+- * {@code null} to disable TLS NPN/ALPN extension.
+- * @param sessionCacheSize the size of the cache used for storing SSL session objects.
+- * {@code 0} to use the default value.
+- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
+- * {@code 0} to use the default value.
+- * @deprecated use {@link SslContextBuilder}
+- */
+- @Deprecated
+- public OpenSslServerContext(
+- File certChainFile, File keyFile, String keyPassword,
+- Iterable<String> ciphers, Iterable<String> nextProtocols,
+- long sessionCacheSize, long sessionTimeout) throws SSLException {
+- this(certChainFile, keyFile, keyPassword, ciphers,
+- toApplicationProtocolConfig(nextProtocols), sessionCacheSize, sessionTimeout);
- }
-
-- // No cache is currently supported for client side mode.
-- static final class OpenSslClientSessionContext extends OpenSslSessionContext {
-- OpenSslClientSessionContext(ReferenceCountedOpenSslContext context) {
-- super(context);
-- }
--
-- @Override
-- public void setSessionTimeout(int seconds) {
-- if (seconds < 0) {
-- throw new IllegalArgumentException();
-- }
-- }
--
-- @Override
-- public int getSessionTimeout() {
-- return 0;
-- }
--
-- @Override
-- public void setSessionCacheSize(int size) {
-- if (size < 0) {
-- throw new IllegalArgumentException();
-- }
-- }
--
-- @Override
-- public int getSessionCacheSize() {
-- return 0;
-- }
--
-- @Override
-- public void setSessionCacheEnabled(boolean enabled) {
-- // ignored
-- }
--
-- @Override
-- public boolean isSessionCacheEnabled() {
-- return false;
-- }
+- /**
+- * Creates a new instance.
+- *
+- * @param certChainFile an X.509 certificate chain file in PEM format
+- * @param keyFile a PKCS#8 private key file in PEM format
+- * @param keyPassword the password of the {@code keyFile}.
+- * {@code null} if it's not password-protected.
+- * @param ciphers the cipher suites to enable, in the order of preference.
+- * {@code null} to use the default cipher suites.
+- * @param config Application protocol config.
+- * @param sessionCacheSize the size of the cache used for storing SSL session objects.
+- * {@code 0} to use the default value.
+- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
+- * {@code 0} to use the default value.
+- * @deprecated use {@link SslContextBuilder}
+- */
+- @Deprecated
+- public OpenSslServerContext(
+- File certChainFile, File keyFile, String keyPassword, TrustManagerFactory trustManagerFactory,
+- Iterable<String> ciphers, ApplicationProtocolConfig config,
+- long sessionCacheSize, long sessionTimeout) throws SSLException {
+- this(certChainFile, keyFile, keyPassword, trustManagerFactory, ciphers,
+- toNegotiator(config), sessionCacheSize, sessionTimeout);
- }
-
-- private static final class TrustManagerVerifyCallback extends AbstractCertificateVerifier {
-- private final X509TrustManager manager;
--
-- TrustManagerVerifyCallback(OpenSslEngineMap engineMap, X509TrustManager manager) {
-- super(engineMap);
-- this.manager = manager;
-- }
+- /**
+- * Creates a new instance.
+- *
+- * @param certChainFile an X.509 certificate chain file in PEM format
+- * @param keyFile a PKCS#8 private key file in PEM format
+- * @param keyPassword the password of the {@code keyFile}.
+- * {@code null} if it's not password-protected.
+- * @param ciphers the cipher suites to enable, in the order of preference.
+- * {@code null} to use the default cipher suites.
+- * @param apn Application protocol negotiator.
+- * @param sessionCacheSize the size of the cache used for storing SSL session objects.
+- * {@code 0} to use the default value.
+- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
+- * {@code 0} to use the default value.
+- * @deprecated use {@link SslContextBuilder}
+- */
+- @Deprecated
+- public OpenSslServerContext(
+- File certChainFile, File keyFile, String keyPassword, TrustManagerFactory trustManagerFactory,
+- Iterable<String> ciphers, OpenSslApplicationProtocolNegotiator apn,
+- long sessionCacheSize, long sessionTimeout) throws SSLException {
+- this(null, trustManagerFactory, certChainFile, keyFile, keyPassword, null,
+- ciphers, null, apn, sessionCacheSize, sessionTimeout);
+- }
-
-- @Override
-- void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts, String auth)
-- throws Exception {
-- manager.checkServerTrusted(peerCerts, auth);
-- }
+- /**
+- * Creates a new instance.
+- *
+- * @param certChainFile an X.509 certificate chain file in PEM format
+- * @param keyFile a PKCS#8 private key file in PEM format
+- * @param keyPassword the password of the {@code keyFile}.
+- * {@code null} if it's not password-protected.
+- * @param ciphers the cipher suites to enable, in the order of preference.
+- * {@code null} to use the default cipher suites.
+- * @param cipherFilter a filter to apply over the supplied list of ciphers
+- * @param apn Provides a means to configure parameters related to application protocol negotiation.
+- * @param sessionCacheSize the size of the cache used for storing SSL session objects.
+- * {@code 0} to use the default value.
+- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
+- * {@code 0} to use the default value.
+- * @deprecated use {@link SslContextBuilder}
+- */
+- @Deprecated
+- public OpenSslServerContext(
+- File certChainFile, File keyFile, String keyPassword,
+- Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
+- long sessionCacheSize, long sessionTimeout) throws SSLException {
+- this(null, null, certChainFile, keyFile, keyPassword, null,
+- ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout);
- }
-
-- private static final class ExtendedTrustManagerVerifyCallback extends AbstractCertificateVerifier {
-- private final X509ExtendedTrustManager manager;
+- /**
+- * Creates a new instance.
+- *
+- * @param trustCertCollectionFile an X.509 certificate collection file in PEM format.
+- * This provides the certificate collection used for mutual authentication.
+- * {@code null} to use the system default
+- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
+- * that verifies the certificates sent from clients.
+- * {@code null} to use the default or the results of parsing
+- * {@code trustCertCollectionFile}.
+- * @param keyCertChainFile an X.509 certificate chain file in PEM format
+- * @param keyFile a PKCS#8 private key file in PEM format
+- * @param keyPassword the password of the {@code keyFile}.
+- * {@code null} if it's not password-protected.
+- * @param keyManagerFactory the {@link KeyManagerFactory} that provides the {@link KeyManager}s
+- * that is used to encrypt data being sent to clients.
+- * {@code null} to use the default or the results of parsing
+- * {@code keyCertChainFile} and {@code keyFile}.
+- * @param ciphers the cipher suites to enable, in the order of preference.
+- * {@code null} to use the default cipher suites.
+- * @param cipherFilter a filter to apply over the supplied list of ciphers
+- * Only required if {@code provider} is {@link SslProvider#JDK}
+- * @param config Provides a means to configure parameters related to application protocol negotiation.
+- * @param sessionCacheSize the size of the cache used for storing SSL session objects.
+- * {@code 0} to use the default value.
+- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
+- * {@code 0} to use the default value.
+- * @deprecated use {@link SslContextBuilder}
+- */
+- @Deprecated
+- public OpenSslServerContext(
+- File trustCertCollectionFile, TrustManagerFactory trustManagerFactory,
+- File keyCertChainFile, File keyFile, String keyPassword, KeyManagerFactory keyManagerFactory,
+- Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig config,
+- long sessionCacheSize, long sessionTimeout) throws SSLException {
+- this(trustCertCollectionFile, trustManagerFactory, keyCertChainFile, keyFile, keyPassword, keyManagerFactory,
+- ciphers, cipherFilter, toNegotiator(config), sessionCacheSize, sessionTimeout);
+- }
-
-- ExtendedTrustManagerVerifyCallback(OpenSslEngineMap engineMap, X509ExtendedTrustManager manager) {
-- super(engineMap);
-- this.manager = manager;
-- }
+- /**
+- * Creates a new instance.
+- *
+- * @param certChainFile an X.509 certificate chain file in PEM format
+- * @param keyFile a PKCS#8 private key file in PEM format
+- * @param keyPassword the password of the {@code keyFile}.
+- * {@code null} if it's not password-protected.
+- * @param ciphers the cipher suites to enable, in the order of preference.
+- * {@code null} to use the default cipher suites.
+- * @param cipherFilter a filter to apply over the supplied list of ciphers
+- * @param config Application protocol config.
+- * @param sessionCacheSize the size of the cache used for storing SSL session objects.
+- * {@code 0} to use the default value.
+- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
+- * {@code 0} to use the default value.
+- * @deprecated use {@link SslContextBuilder}
+- */
+- @Deprecated
+- public OpenSslServerContext(File certChainFile, File keyFile, String keyPassword,
+- TrustManagerFactory trustManagerFactory, Iterable<String> ciphers,
+- CipherSuiteFilter cipherFilter, ApplicationProtocolConfig config,
+- long sessionCacheSize, long sessionTimeout) throws SSLException {
+- this(null, trustManagerFactory, certChainFile, keyFile, keyPassword, null, ciphers, cipherFilter,
+- toNegotiator(config), sessionCacheSize, sessionTimeout);
+- }
-
-- @Override
-- void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts, String auth)
-- throws Exception {
-- manager.checkServerTrusted(peerCerts, auth, engine);
-- }
+- /**
+- * Creates a new instance.
+- *
+- * @param certChainFile an X.509 certificate chain file in PEM format
+- * @param keyFile a PKCS#8 private key file in PEM format
+- * @param keyPassword the password of the {@code keyFile}.
+- * {@code null} if it's not password-protected.
+- * @param ciphers the cipher suites to enable, in the order of preference.
+- * {@code null} to use the default cipher suites.
+- * @param cipherFilter a filter to apply over the supplied list of ciphers
+- * @param apn Application protocol negotiator.
+- * @param sessionCacheSize the size of the cache used for storing SSL session objects.
+- * {@code 0} to use the default value.
+- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
+- * {@code 0} to use the default value.
+- * @deprecated use {@link SslContextBuilder}}
+- */
+- @Deprecated
+- public OpenSslServerContext(
+- File certChainFile, File keyFile, String keyPassword, TrustManagerFactory trustManagerFactory,
+- Iterable<String> ciphers, CipherSuiteFilter cipherFilter, OpenSslApplicationProtocolNegotiator apn,
+- long sessionCacheSize, long sessionTimeout) throws SSLException {
+- this(null, trustManagerFactory, certChainFile, keyFile, keyPassword, null, ciphers, cipherFilter,
+- apn, sessionCacheSize, sessionTimeout);
- }
-
-- private static final class OpenSslCertificateRequestedCallback implements CertificateRequestedCallback {
-- private final OpenSslEngineMap engineMap;
-- private final OpenSslKeyMaterialManager keyManagerHolder;
+- /**
+- * Creates a new instance.
+- *
+- *
+- * @param trustCertCollectionFile an X.509 certificate collection file in PEM format.
+- * This provides the certificate collection used for mutual authentication.
+- * {@code null} to use the system default
+- * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
+- * that verifies the certificates sent from clients.
+- * {@code null} to use the default or the results of parsing
+- * {@code trustCertCollectionFile}.
+- * @param keyCertChainFile an X.509 certificate chain file in PEM format
+- * @param keyFile a PKCS#8 private key file in PEM format
+- * @param keyPassword the password of the {@code keyFile}.
+- * {@code null} if it's not password-protected.
+- * @param keyManagerFactory the {@link KeyManagerFactory} that provides the {@link KeyManager}s
+- * that is used to encrypt data being sent to clients.
+- * {@code null} to use the default or the results of parsing
+- * {@code keyCertChainFile} and {@code keyFile}.
+- * @param ciphers the cipher suites to enable, in the order of preference.
+- * {@code null} to use the default cipher suites.
+- * @param cipherFilter a filter to apply over the supplied list of ciphers
+- * Only required if {@code provider} is {@link SslProvider#JDK}
+- * @param apn Application Protocol Negotiator object
+- * @param sessionCacheSize the size of the cache used for storing SSL session objects.
+- * {@code 0} to use the default value.
+- * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
+- * {@code 0} to use the default value.
+- * @deprecated use {@link SslContextBuilder}
+- */
+- @Deprecated
+- public OpenSslServerContext(
+- File trustCertCollectionFile, TrustManagerFactory trustManagerFactory,
+- File keyCertChainFile, File keyFile, String keyPassword, KeyManagerFactory keyManagerFactory,
+- Iterable<String> ciphers, CipherSuiteFilter cipherFilter, OpenSslApplicationProtocolNegotiator apn,
+- long sessionCacheSize, long sessionTimeout) throws SSLException {
+- this(toX509CertificatesInternal(trustCertCollectionFile), trustManagerFactory,
+- toX509CertificatesInternal(keyCertChainFile), toPrivateKeyInternal(keyFile, keyPassword),
+- keyPassword, keyManagerFactory, ciphers, cipherFilter,
+- apn, sessionCacheSize, sessionTimeout, ClientAuth.NONE, null, false, false, KeyStore.getDefaultType());
+- }
-
-- OpenSslCertificateRequestedCallback(OpenSslEngineMap engineMap, OpenSslKeyMaterialManager keyManagerHolder) {
-- this.engineMap = engineMap;
-- this.keyManagerHolder = keyManagerHolder;
-- }
+- OpenSslServerContext(
+- X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory,
+- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory,
+- Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
+- long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[] protocols, boolean startTls,
+- boolean enableOcsp, String keyStore) throws SSLException {
+- this(trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory, ciphers,
+- cipherFilter, toNegotiator(apn), sessionCacheSize, sessionTimeout, clientAuth, protocols, startTls,
+- enableOcsp, keyStore);
+- }
-
-- @Override
-- public KeyMaterial requested(long ssl, byte[] keyTypeBytes, byte[][] asn1DerEncodedPrincipals) {
-- final ReferenceCountedOpenSslEngine engine = engineMap.get(ssl);
-- try {
-- final Set<String> keyTypesSet = supportedClientKeyTypes(keyTypeBytes);
-- final String[] keyTypes = keyTypesSet.toArray(new String[keyTypesSet.size()]);
-- final X500Principal[] issuers;
-- if (asn1DerEncodedPrincipals == null) {
-- issuers = null;
-- } else {
-- issuers = new X500Principal[asn1DerEncodedPrincipals.length];
-- for (int i = 0; i < asn1DerEncodedPrincipals.length; i++) {
-- issuers[i] = new X500Principal(asn1DerEncodedPrincipals[i]);
-- }
-- }
-- return keyManagerHolder.keyMaterial(engine, keyTypes, issuers);
-- } catch (Throwable cause) {
-- logger.debug("request of key failed", cause);
-- SSLHandshakeException e = new SSLHandshakeException("General OpenSslEngine problem");
-- e.initCause(cause);
-- engine.handshakeException = e;
-- return null;
-- }
-- }
+- @SuppressWarnings("deprecation")
+- private OpenSslServerContext(
+- X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory,
+- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory,
+- Iterable<String> ciphers, CipherSuiteFilter cipherFilter, OpenSslApplicationProtocolNegotiator apn,
+- long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[] protocols, boolean startTls,
+- boolean enableOcsp, String keyStore) throws SSLException {
+- super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, SSL.SSL_MODE_SERVER, keyCertChain,
+- clientAuth, protocols, startTls, enableOcsp);
-
-- /**
-- * Gets the supported key types for client certificates.
-- *
-- * @param clientCertificateTypes {@code ClientCertificateType} values provided by the server.
-- * See https://www.ietf.org/assignments/tls-parameters/tls-parameters.xml.
-- * @return supported key types that can be used in {@code X509KeyManager.chooseClientAlias} and
-- * {@code X509ExtendedKeyManager.chooseEngineClientAlias}.
-- */
-- private static Set<String> supportedClientKeyTypes(byte[] clientCertificateTypes) {
-- Set<String> result = new HashSet<String>(clientCertificateTypes.length);
-- for (byte keyTypeCode : clientCertificateTypes) {
-- String keyType = clientKeyType(keyTypeCode);
-- if (keyType == null) {
-- // Unsupported client key type -- ignore
-- continue;
-- }
-- result.add(keyType);
+- // Create a new SSL_CTX and configure it.
+- boolean success = false;
+- try {
+- OpenSslKeyMaterialProvider.validateKeyMaterialSupported(keyCertChain, key, keyPassword);
+- sessionContext = newSessionContext(this, ctx, engineMap, trustCertCollection, trustManagerFactory,
+- keyCertChain, key, keyPassword, keyManagerFactory, keyStore);
+- success = true;
+- } finally {
+- if (!success) {
+- release();
- }
-- return result;
- }
+- }
-
-- private static String clientKeyType(byte clientCertificateType) {
-- // See also http://www.ietf.org/assignments/tls-parameters/tls-parameters.xml
-- switch (clientCertificateType) {
-- case CertificateRequestedCallback.TLS_CT_RSA_SIGN:
-- return OpenSslKeyMaterialManager.KEY_TYPE_RSA; // RFC rsa_sign
-- case CertificateRequestedCallback.TLS_CT_RSA_FIXED_DH:
-- return OpenSslKeyMaterialManager.KEY_TYPE_DH_RSA; // RFC rsa_fixed_dh
-- case CertificateRequestedCallback.TLS_CT_ECDSA_SIGN:
-- return OpenSslKeyMaterialManager.KEY_TYPE_EC; // RFC ecdsa_sign
-- case CertificateRequestedCallback.TLS_CT_RSA_FIXED_ECDH:
-- return OpenSslKeyMaterialManager.KEY_TYPE_EC_RSA; // RFC rsa_fixed_ecdh
-- case CertificateRequestedCallback.TLS_CT_ECDSA_FIXED_ECDH:
-- return OpenSslKeyMaterialManager.KEY_TYPE_EC_EC; // RFC ecdsa_fixed_ecdh
-- default:
-- return null;
-- }
-- }
+- @Override
+- public OpenSslServerSessionContext sessionContext() {
+- return sessionContext;
- }
-}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslContext.java b/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslContext.java
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerSessionContext.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslServerSessionContext.java
deleted file mode 100644
-index ee049ab..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslContext.java
+index 691ee0b661..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerSessionContext.java
+++ /dev/null
-@@ -1,867 +0,0 @@
+@@ -1,124 +0,0 @@
-/*
-- * Copyright 2016 The Netty Project
+- * Copyright 2014 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
@@ -2612,864 +2910,874 @@ index ee049ab..0000000
- */
-package io.netty.handler.ssl;
-
--import io.netty.buffer.ByteBuf;
--import io.netty.buffer.ByteBufAllocator;
--import io.netty.internal.tcnative.CertificateVerifier;
-import io.netty.internal.tcnative.SSL;
-import io.netty.internal.tcnative.SSLContext;
--import io.netty.util.AbstractReferenceCounted;
--import io.netty.util.ReferenceCounted;
--import io.netty.util.ResourceLeakDetector;
--import io.netty.util.ResourceLeakDetectorFactory;
--import io.netty.util.ResourceLeakTracker;
--import io.netty.util.internal.PlatformDependent;
--import io.netty.util.internal.StringUtil;
--import io.netty.util.internal.SystemPropertyUtil;
--import io.netty.util.internal.logging.InternalLogger;
--import io.netty.util.internal.logging.InternalLoggerFactory;
--
--import java.security.AccessController;
--import java.security.PrivateKey;
--import java.security.PrivilegedAction;
--import java.security.cert.CertPathValidatorException;
--import java.security.cert.Certificate;
--import java.security.cert.CertificateExpiredException;
--import java.security.cert.CertificateNotYetValidException;
--import java.security.cert.CertificateRevokedException;
--import java.security.cert.X509Certificate;
--import java.util.ArrayList;
--import java.util.Arrays;
--import java.util.Collections;
--import java.util.List;
--import java.util.Map;
-
-import java.util.concurrent.locks.Lock;
--import java.util.concurrent.locks.ReadWriteLock;
--import java.util.concurrent.locks.ReentrantReadWriteLock;
--import javax.net.ssl.KeyManager;
--import javax.net.ssl.SSLEngine;
--import javax.net.ssl.SSLException;
--import javax.net.ssl.SSLHandshakeException;
--import javax.net.ssl.TrustManager;
--import javax.net.ssl.X509ExtendedKeyManager;
--import javax.net.ssl.X509ExtendedTrustManager;
--import javax.net.ssl.X509KeyManager;
--import javax.net.ssl.X509TrustManager;
-
--import static io.netty.util.internal.ObjectUtil.checkNotNull;
--import static io.netty.util.internal.ObjectUtil.checkPositiveOrZero;
-
-/**
-- * An implementation of {@link SslContext} which works with libraries that support the
-- * <a href="https://www.openssl.org/">OpenSsl</a> C library API.
-- * <p>Instances of this class must be {@link #release() released} or else native memory will leak!
-- *
-- * <p>Instances of this class <strong>must not</strong> be released before any {@link ReferenceCountedOpenSslEngine}
-- * which depends upon the instance of this class is released. Otherwise if any method of
-- * {@link ReferenceCountedOpenSslEngine} is called which uses this class's JNI resources the JVM may crash.
+- * {@link OpenSslSessionContext} implementation which offers extra methods which are only useful for the server-side.
- */
--public abstract class ReferenceCountedOpenSslContext extends SslContext implements ReferenceCounted {
-- private static final InternalLogger logger =
-- InternalLoggerFactory.getInstance(ReferenceCountedOpenSslContext.class);
-- /**
-- * To make it easier for users to replace JDK implementation with OpenSsl version we also use
-- * {@code jdk.tls.rejectClientInitiatedRenegotiation} to allow disabling client initiated renegotiation.
-- * Java8+ uses this system property as well.
-- * <p>
-- * See also <a href="http://blog.ivanristic.com/2014/03/ssl-tls-improvements-in-java-8.html">
-- * Significant SSL/TLS improvements in Java 8</a>
-- */
-- private static final boolean JDK_REJECT_CLIENT_INITIATED_RENEGOTIATION =
-- AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
-- @Override
-- public Boolean run() {
-- return SystemPropertyUtil.getBoolean("jdk.tls.rejectClientInitiatedRenegotiation", false);
-- }
-- });
+-public final class OpenSslServerSessionContext extends OpenSslSessionContext {
+- OpenSslServerSessionContext(ReferenceCountedOpenSslContext context, OpenSslKeyMaterialProvider provider) {
+- super(context, provider);
+- }
-
-- private static final int DEFAULT_BIO_NON_APPLICATION_BUFFER_SIZE =
-- AccessController.doPrivileged(new PrivilegedAction<Integer>() {
-- @Override
-- public Integer run() {
-- return Math.max(1,
-- SystemPropertyUtil.getInt("io.netty.handler.ssl.openssl.bioNonApplicationBufferSize",
-- 2048));
-- }
-- });
+- @Override
+- public void setSessionTimeout(int seconds) {
+- if (seconds < 0) {
+- throw new IllegalArgumentException();
+- }
+- Lock writerLock = context.ctxLock.writeLock();
+- writerLock.lock();
+- try {
+- SSLContext.setSessionCacheTimeout(context.ctx, seconds);
+- } finally {
+- writerLock.unlock();
+- }
+- }
-
-- private static final List<String> DEFAULT_CIPHERS;
-- private static final Integer DH_KEY_LENGTH;
-- private static final ResourceLeakDetector<ReferenceCountedOpenSslContext> leakDetector =
-- ResourceLeakDetectorFactory.instance().newResourceLeakDetector(ReferenceCountedOpenSslContext.class);
+- @Override
+- public int getSessionTimeout() {
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- try {
+- return (int) SSLContext.getSessionCacheTimeout(context.ctx);
+- } finally {
+- readerLock.unlock();
+- }
+- }
-
-- // TODO: Maybe make configurable ?
-- protected static final int VERIFY_DEPTH = 10;
+- @Override
+- public void setSessionCacheSize(int size) {
+- if (size < 0) {
+- throw new IllegalArgumentException();
+- }
+- Lock writerLock = context.ctxLock.writeLock();
+- writerLock.lock();
+- try {
+- SSLContext.setSessionCacheSize(context.ctx, size);
+- } finally {
+- writerLock.unlock();
+- }
+- }
-
-- /**
-- * The OpenSSL SSL_CTX object.
-- *
-- * <strong>{@link #ctxLock} must be hold while using ctx!</strong>
-- */
-- protected long ctx;
-- private final List<String> unmodifiableCiphers;
-- private final long sessionCacheSize;
-- private final long sessionTimeout;
-- private final OpenSslApplicationProtocolNegotiator apn;
-- private final int mode;
+- @Override
+- public int getSessionCacheSize() {
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- try {
+- return (int) SSLContext.getSessionCacheSize(context.ctx);
+- } finally {
+- readerLock.unlock();
+- }
+- }
-
-- // Reference Counting
-- private final ResourceLeakTracker<ReferenceCountedOpenSslContext> leak;
-- private final AbstractReferenceCounted refCnt = new AbstractReferenceCounted() {
-- @Override
-- public ReferenceCounted touch(Object hint) {
-- if (leak != null) {
-- leak.record(hint);
-- }
+- @Override
+- public void setSessionCacheEnabled(boolean enabled) {
+- long mode = enabled ? SSL.SSL_SESS_CACHE_SERVER : SSL.SSL_SESS_CACHE_OFF;
-
-- return ReferenceCountedOpenSslContext.this;
+- Lock writerLock = context.ctxLock.writeLock();
+- writerLock.lock();
+- try {
+- SSLContext.setSessionCacheMode(context.ctx, mode);
+- } finally {
+- writerLock.unlock();
- }
+- }
-
-- @Override
-- protected void deallocate() {
-- destroy();
-- if (leak != null) {
-- boolean closed = leak.close(ReferenceCountedOpenSslContext.this);
-- assert closed;
-- }
+- @Override
+- public boolean isSessionCacheEnabled() {
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- try {
+- return SSLContext.getSessionCacheMode(context.ctx) == SSL.SSL_SESS_CACHE_SERVER;
+- } finally {
+- readerLock.unlock();
- }
-- };
--
-- final Certificate[] keyCertChain;
-- final ClientAuth clientAuth;
-- final String[] protocols;
-- final boolean enableOcsp;
-- final OpenSslEngineMap engineMap = new DefaultOpenSslEngineMap();
-- final ReadWriteLock ctxLock = new ReentrantReadWriteLock();
--
-- private volatile boolean rejectRemoteInitiatedRenegotiation;
-- private volatile int bioNonApplicationBufferSize = DEFAULT_BIO_NON_APPLICATION_BUFFER_SIZE;
+- }
-
-- static final OpenSslApplicationProtocolNegotiator NONE_PROTOCOL_NEGOTIATOR =
-- new OpenSslApplicationProtocolNegotiator() {
-- @Override
-- public ApplicationProtocolConfig.Protocol protocol() {
-- return ApplicationProtocolConfig.Protocol.NONE;
-- }
+- /**
+- * Set the context within which session be reused (server side only)
+- * See <a href="http://www.openssl.org/docs/ssl/SSL_CTX_set_session_id_context.html">
+- * man SSL_CTX_set_session_id_context</a>
+- *
+- * @param sidCtx can be any kind of binary data, it is therefore possible to use e.g. the name
+- * of the application and/or the hostname and/or service name
+- * @return {@code true} if success, {@code false} otherwise.
+- */
+- public boolean setSessionIdContext(byte[] sidCtx) {
+- Lock writerLock = context.ctxLock.writeLock();
+- writerLock.lock();
+- try {
+- return SSLContext.setSessionIdContext(context.ctx, sidCtx);
+- } finally {
+- writerLock.unlock();
+- }
+- }
+-}
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionContext.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionContext.java
+deleted file mode 100644
+index 5d471d34fb..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionContext.java
++++ /dev/null
+@@ -1,158 +0,0 @@
+-/*
+- * Copyright 2014 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- * http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-package io.netty.handler.ssl;
-
-- @Override
-- public List<String> protocols() {
-- return Collections.emptyList();
-- }
+-import io.netty.internal.tcnative.SSL;
+-import io.netty.internal.tcnative.SSLContext;
+-import io.netty.internal.tcnative.SessionTicketKey;
+-import io.netty.util.internal.ObjectUtil;
-
-- @Override
-- public ApplicationProtocolConfig.SelectorFailureBehavior selectorFailureBehavior() {
-- return ApplicationProtocolConfig.SelectorFailureBehavior.CHOOSE_MY_LAST_PROTOCOL;
-- }
+-import javax.net.ssl.SSLSession;
+-import javax.net.ssl.SSLSessionContext;
+-import java.util.Arrays;
+-import java.util.Enumeration;
+-import java.util.NoSuchElementException;
+-import java.util.concurrent.locks.Lock;
-
-- @Override
-- public ApplicationProtocolConfig.SelectedListenerFailureBehavior selectedListenerFailureBehavior() {
-- return ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT;
-- }
-- };
+-/**
+- * OpenSSL specific {@link SSLSessionContext} implementation.
+- */
+-public abstract class OpenSslSessionContext implements SSLSessionContext {
+- private static final Enumeration<byte[]> EMPTY = new EmptyEnumeration();
-
-- static {
-- List<String> ciphers = new ArrayList<String>();
-- // XXX: Make sure to sync this list with JdkSslEngineFactory.
-- Collections.addAll(
-- ciphers,
-- "ECDHE-ECDSA-AES256-GCM-SHA384",
-- "ECDHE-ECDSA-AES128-GCM-SHA256",
-- "ECDHE-RSA-AES128-GCM-SHA256",
-- "ECDHE-RSA-AES128-SHA",
-- "ECDHE-RSA-AES256-SHA",
-- "AES128-GCM-SHA256",
-- "AES128-SHA",
-- "AES256-SHA");
-- DEFAULT_CIPHERS = Collections.unmodifiableList(ciphers);
+- private final OpenSslSessionStats stats;
-
-- if (logger.isDebugEnabled()) {
-- logger.debug("Default cipher suite (OpenSSL): " + ciphers);
-- }
+- // The OpenSslKeyMaterialProvider is not really used by the OpenSslSessionContext but only be stored here
+- // to make it easier to destroy it later because the ReferenceCountedOpenSslContext will hold a reference
+- // to OpenSslSessionContext.
+- private final OpenSslKeyMaterialProvider provider;
-
-- Integer dhLen = null;
+- final ReferenceCountedOpenSslContext context;
-
-- try {
-- String dhKeySize = AccessController.doPrivileged(new PrivilegedAction<String>() {
-- @Override
-- public String run() {
-- return SystemPropertyUtil.get("jdk.tls.ephemeralDHKeySize");
-- }
-- });
-- if (dhKeySize != null) {
-- try {
-- dhLen = Integer.valueOf(dhKeySize);
-- } catch (NumberFormatException e) {
-- logger.debug("ReferenceCountedOpenSslContext supports -Djdk.tls.ephemeralDHKeySize={int}, but got: "
-- + dhKeySize);
-- }
-- }
-- } catch (Throwable ignore) {
-- // ignore
-- }
-- DH_KEY_LENGTH = dhLen;
+- // IMPORTANT: We take the OpenSslContext and not just the long (which points the native instance) to prevent
+- // the GC to collect OpenSslContext as this would also free the pointer and so could result in a
+- // segfault when the user calls any of the methods here that try to pass the pointer down to the native
+- // level.
+- OpenSslSessionContext(ReferenceCountedOpenSslContext context, OpenSslKeyMaterialProvider provider) {
+- this.context = context;
+- this.provider = provider;
+- stats = new OpenSslSessionStats(context);
- }
-
-- ReferenceCountedOpenSslContext(Iterable<String> ciphers, CipherSuiteFilter cipherFilter,
-- ApplicationProtocolConfig apnCfg, long sessionCacheSize, long sessionTimeout,
-- int mode, Certificate[] keyCertChain, ClientAuth clientAuth, String[] protocols,
-- boolean startTls, boolean enableOcsp, boolean leakDetection) throws SSLException {
-- this(ciphers, cipherFilter, toNegotiator(apnCfg), sessionCacheSize, sessionTimeout, mode, keyCertChain,
-- clientAuth, protocols, startTls, enableOcsp, leakDetection);
+- final boolean useKeyManager() {
+- return provider != null;
- }
-
-- ReferenceCountedOpenSslContext(Iterable<String> ciphers, CipherSuiteFilter cipherFilter,
-- OpenSslApplicationProtocolNegotiator apn, long sessionCacheSize,
-- long sessionTimeout, int mode, Certificate[] keyCertChain,
-- ClientAuth clientAuth, String[] protocols, boolean startTls, boolean enableOcsp,
-- boolean leakDetection) throws SSLException {
-- super(startTls);
+- @Override
+- public SSLSession getSession(byte[] bytes) {
+- ObjectUtil.checkNotNull(bytes, "bytes");
+- return null;
+- }
-
-- OpenSsl.ensureAvailability();
+- @Override
+- public Enumeration<byte[]> getIds() {
+- return EMPTY;
+- }
-
-- if (enableOcsp && !OpenSsl.isOcspSupported()) {
-- throw new IllegalStateException("OCSP is not supported.");
+- /**
+- * Sets the SSL session ticket keys of this context.
+- * @deprecated use {@link #setTicketKeys(OpenSslSessionTicketKey...)}.
+- */
+- @Deprecated
+- public void setTicketKeys(byte[] keys) {
+- if (keys.length % SessionTicketKey.TICKET_KEY_SIZE != 0) {
+- throw new IllegalArgumentException("keys.length % " + SessionTicketKey.TICKET_KEY_SIZE + " != 0");
- }
--
-- if (mode != SSL.SSL_MODE_SERVER && mode != SSL.SSL_MODE_CLIENT) {
-- throw new IllegalArgumentException("mode most be either SSL.SSL_MODE_SERVER or SSL.SSL_MODE_CLIENT");
+- SessionTicketKey[] tickets = new SessionTicketKey[keys.length / SessionTicketKey.TICKET_KEY_SIZE];
+- for (int i = 0, a = 0; i < tickets.length; i++) {
+- byte[] name = Arrays.copyOfRange(keys, a, SessionTicketKey.NAME_SIZE);
+- a += SessionTicketKey.NAME_SIZE;
+- byte[] hmacKey = Arrays.copyOfRange(keys, a, SessionTicketKey.HMAC_KEY_SIZE);
+- i += SessionTicketKey.HMAC_KEY_SIZE;
+- byte[] aesKey = Arrays.copyOfRange(keys, a, SessionTicketKey.AES_KEY_SIZE);
+- a += SessionTicketKey.AES_KEY_SIZE;
+- tickets[i] = new SessionTicketKey(name, hmacKey, aesKey);
- }
-- leak = leakDetection ? leakDetector.track(this) : null;
-- this.mode = mode;
-- this.clientAuth = isServer() ? checkNotNull(clientAuth, "clientAuth") : ClientAuth.NONE;
-- this.protocols = protocols;
-- this.enableOcsp = enableOcsp;
--
-- if (mode == SSL.SSL_MODE_SERVER) {
-- rejectRemoteInitiatedRenegotiation =
-- JDK_REJECT_CLIENT_INITIATED_RENEGOTIATION;
+- Lock writerLock = context.ctxLock.writeLock();
+- writerLock.lock();
+- try {
+- SSLContext.clearOptions(context.ctx, SSL.SSL_OP_NO_TICKET);
+- SSLContext.setSessionTicketKeys(context.ctx, tickets);
+- } finally {
+- writerLock.unlock();
- }
-- this.keyCertChain = keyCertChain == null ? null : keyCertChain.clone();
-- final List<String> convertedCiphers;
-- if (ciphers == null) {
-- convertedCiphers = null;
-- } else {
-- convertedCiphers = new ArrayList<String>();
-- for (String c : ciphers) {
-- if (c == null) {
-- break;
-- }
+- }
-
-- String converted = CipherSuiteConverter.toOpenSsl(c);
-- if (converted != null) {
-- c = converted;
-- }
-- convertedCiphers.add(c);
+- /**
+- * Sets the SSL session ticket keys of this context. Depending on the underlying native library you may omit the
+- * argument or pass an empty array and so let the native library handle the key generation and rotating for you.
+- * If this is supported by the underlying native library should be checked in this case. For example
+- * <a href="https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.ht...">
+- * BoringSSL</a> is known to support this.
+- */
+- public void setTicketKeys(OpenSslSessionTicketKey... keys) {
+- ObjectUtil.checkNotNull(keys, "keys");
+- SessionTicketKey[] ticketKeys = new SessionTicketKey[keys.length];
+- for (int i = 0; i < ticketKeys.length; i++) {
+- ticketKeys[i] = keys[i].key;
+- }
+- Lock writerLock = context.ctxLock.writeLock();
+- writerLock.lock();
+- try {
+- SSLContext.clearOptions(context.ctx, SSL.SSL_OP_NO_TICKET);
+- if (ticketKeys.length > 0) {
+- SSLContext.setSessionTicketKeys(context.ctx, ticketKeys);
- }
+- } finally {
+- writerLock.unlock();
- }
+- }
-
-- unmodifiableCiphers = Arrays.asList(checkNotNull(cipherFilter, "cipherFilter").filterCipherSuites(
-- convertedCiphers, DEFAULT_CIPHERS, OpenSsl.availableOpenSslCipherSuites()));
+- /**
+- * Enable or disable caching of SSL sessions.
+- */
+- public abstract void setSessionCacheEnabled(boolean enabled);
-
-- this.apn = checkNotNull(apn, "apn");
+- /**
+- * Return {@code true} if caching of SSL sessions is enabled, {@code false} otherwise.
+- */
+- public abstract boolean isSessionCacheEnabled();
-
-- // Create a new SSL_CTX and configure it.
-- boolean success = false;
-- try {
-- try {
-- ctx = SSLContext.make(SSL.SSL_PROTOCOL_ALL, mode);
-- } catch (Exception e) {
-- throw new SSLException("failed to create an SSL_CTX", e);
-- }
+- /**
+- * Returns the stats of this context.
+- */
+- public OpenSslSessionStats stats() {
+- return stats;
+- }
+-
+- final void destroy() {
+- if (provider != null) {
+- provider.destroy();
+- }
+- }
+-
+- private static final class EmptyEnumeration implements Enumeration<byte[]> {
+- @Override
+- public boolean hasMoreElements() {
+- return false;
+- }
-
-- SSLContext.setOptions(ctx, SSLContext.getOptions(ctx) |
-- SSL.SSL_OP_NO_SSLv2 |
-- SSL.SSL_OP_NO_SSLv3 |
-- SSL.SSL_OP_CIPHER_SERVER_PREFERENCE |
+- @Override
+- public byte[] nextElement() {
+- throw new NoSuchElementException();
+- }
+- }
+-}
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionStats.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionStats.java
+deleted file mode 100644
+index f49b95f3ba..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionStats.java
++++ /dev/null
+@@ -1,253 +0,0 @@
+-/*
+- * Copyright 2014 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- * http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
-
-- // We do not support compression at the moment so we should explicitly disable it.
-- SSL.SSL_OP_NO_COMPRESSION |
+-package io.netty.handler.ssl;
-
-- // Disable ticket support by default to be more inline with SSLEngineImpl of the JDK.
-- // This also let SSLSession.getId() work the same way for the JDK implementation and the
-- // OpenSSLEngine. If tickets are supported SSLSession.getId() will only return an ID on the
-- // server-side if it could make use of tickets.
-- SSL.SSL_OP_NO_TICKET);
+-import io.netty.internal.tcnative.SSLContext;
-
-- // We need to enable SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER as the memory address may change between
-- // calling OpenSSLEngine.wrap(...).
-- // See https://github.com/netty/netty-tcnative/issues/100
-- SSLContext.setMode(ctx, SSLContext.getMode(ctx) | SSL.SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
+-import java.util.concurrent.locks.Lock;
-
-- if (DH_KEY_LENGTH != null) {
-- SSLContext.setTmpDHLength(ctx, DH_KEY_LENGTH);
-- }
+-/**
+- * Stats exposed by an OpenSSL session context.
+- *
+- * @see <a href="https://www.openssl.org/docs/manmaster/man3/SSL_CTX_sess_number.html">SSL_CTX_sess_number</a>
+- */
+-public final class OpenSslSessionStats {
-
-- /* List the ciphers that are permitted to negotiate. */
-- try {
-- SSLContext.setCipherSuite(ctx, CipherSuiteConverter.toOpenSsl(unmodifiableCiphers));
-- } catch (SSLException e) {
-- throw e;
-- } catch (Exception e) {
-- throw new SSLException("failed to set cipher suite: " + unmodifiableCiphers, e);
-- }
+- private final ReferenceCountedOpenSslContext context;
-
-- List<String> nextProtoList = apn.protocols();
-- /* Set next protocols for next protocol negotiation extension, if specified */
-- if (!nextProtoList.isEmpty()) {
-- String[] appProtocols = nextProtoList.toArray(new String[nextProtoList.size()]);
-- int selectorBehavior = opensslSelectorFailureBehavior(apn.selectorFailureBehavior());
+- // IMPORTANT: We take the OpenSslContext and not just the long (which points the native instance) to prevent
+- // the GC to collect OpenSslContext as this would also free the pointer and so could result in a
+- // segfault when the user calls any of the methods here that try to pass the pointer down to the native
+- // level.
+- OpenSslSessionStats(ReferenceCountedOpenSslContext context) {
+- this.context = context;
+- }
-
-- switch (apn.protocol()) {
-- case NPN:
-- SSLContext.setNpnProtos(ctx, appProtocols, selectorBehavior);
-- break;
-- case ALPN:
-- SSLContext.setAlpnProtos(ctx, appProtocols, selectorBehavior);
-- break;
-- case NPN_AND_ALPN:
-- SSLContext.setNpnProtos(ctx, appProtocols, selectorBehavior);
-- SSLContext.setAlpnProtos(ctx, appProtocols, selectorBehavior);
-- break;
-- default:
-- throw new Error();
-- }
-- }
+- /**
+- * Returns the current number of sessions in the internal session cache.
+- */
+- public long number() {
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- try {
+- return SSLContext.sessionNumber(context.ctx);
+- } finally {
+- readerLock.unlock();
+- }
+- }
-
-- /* Set session cache size, if specified */
-- if (sessionCacheSize > 0) {
-- this.sessionCacheSize = sessionCacheSize;
-- SSLContext.setSessionCacheSize(ctx, sessionCacheSize);
-- } else {
-- // Get the default session cache size using SSLContext.setSessionCacheSize()
-- this.sessionCacheSize = sessionCacheSize = SSLContext.setSessionCacheSize(ctx, 20480);
-- // Revert the session cache size to the default value.
-- SSLContext.setSessionCacheSize(ctx, sessionCacheSize);
-- }
+- /**
+- * Returns the number of started SSL/TLS handshakes in client mode.
+- */
+- public long connect() {
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- try {
+- return SSLContext.sessionConnect(context.ctx);
+- } finally {
+- readerLock.unlock();
+- }
+- }
-
-- /* Set session timeout, if specified */
-- if (sessionTimeout > 0) {
-- this.sessionTimeout = sessionTimeout;
-- SSLContext.setSessionCacheTimeout(ctx, sessionTimeout);
-- } else {
-- // Get the default session timeout using SSLContext.setSessionCacheTimeout()
-- this.sessionTimeout = sessionTimeout = SSLContext.setSessionCacheTimeout(ctx, 300);
-- // Revert the session timeout to the default value.
-- SSLContext.setSessionCacheTimeout(ctx, sessionTimeout);
-- }
+- /**
+- * Returns the number of successfully established SSL/TLS sessions in client mode.
+- */
+- public long connectGood() {
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- try {
+- return SSLContext.sessionConnectGood(context.ctx);
+- } finally {
+- readerLock.unlock();
+- }
+- }
-
-- if (enableOcsp) {
-- SSLContext.enableOcsp(ctx, isClient());
-- }
-- success = true;
+- /**
+- * Returns the number of start renegotiations in client mode.
+- */
+- public long connectRenegotiate() {
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- try {
+- return SSLContext.sessionConnectRenegotiate(context.ctx);
- } finally {
-- if (!success) {
-- release();
-- }
+- readerLock.unlock();
- }
- }
-
-- private static int opensslSelectorFailureBehavior(ApplicationProtocolConfig.SelectorFailureBehavior behavior) {
-- switch (behavior) {
-- case NO_ADVERTISE:
-- return SSL.SSL_SELECTOR_FAILURE_NO_ADVERTISE;
-- case CHOOSE_MY_LAST_PROTOCOL:
-- return SSL.SSL_SELECTOR_FAILURE_CHOOSE_MY_LAST_PROTOCOL;
-- default:
-- throw new Error();
+- /**
+- * Returns the number of started SSL/TLS handshakes in server mode.
+- */
+- public long accept() {
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- try {
+- return SSLContext.sessionAccept(context.ctx);
+- } finally {
+- readerLock.unlock();
- }
- }
-
-- @Override
-- public final List<String> cipherSuites() {
-- return unmodifiableCiphers;
+- /**
+- * Returns the number of successfully established SSL/TLS sessions in server mode.
+- */
+- public long acceptGood() {
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- try {
+- return SSLContext.sessionAcceptGood(context.ctx);
+- } finally {
+- readerLock.unlock();
+- }
- }
-
-- @Override
-- public final long sessionCacheSize() {
-- return sessionCacheSize;
+- /**
+- * Returns the number of start renegotiations in server mode.
+- */
+- public long acceptRenegotiate() {
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- try {
+- return SSLContext.sessionAcceptRenegotiate(context.ctx);
+- } finally {
+- readerLock.unlock();
+- }
- }
-
-- @Override
-- public final long sessionTimeout() {
-- return sessionTimeout;
+- /**
+- * Returns the number of successfully reused sessions. In client mode, a session set with {@code SSL_set_session}
+- * successfully reused is counted as a hit. In server mode, a session successfully retrieved from internal or
+- * external cache is counted as a hit.
+- */
+- public long hits() {
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- try {
+- return SSLContext.sessionHits(context.ctx);
+- } finally {
+- readerLock.unlock();
+- }
- }
-
-- @Override
-- public ApplicationProtocolNegotiator applicationProtocolNegotiator() {
-- return apn;
+- /**
+- * Returns the number of successfully retrieved sessions from the external session cache in server mode.
+- */
+- public long cbHits() {
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- try {
+- return SSLContext.sessionCbHits(context.ctx);
+- } finally {
+- readerLock.unlock();
+- }
- }
-
-- @Override
-- public final boolean isClient() {
-- return mode == SSL.SSL_MODE_CLIENT;
+- /**
+- * Returns the number of sessions proposed by clients that were not found in the internal session cache
+- * in server mode.
+- */
+- public long misses() {
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- try {
+- return SSLContext.sessionMisses(context.ctx);
+- } finally {
+- readerLock.unlock();
+- }
- }
-
-- @Override
-- public final SSLEngine newEngine(ByteBufAllocator alloc, String peerHost, int peerPort) {
-- return newEngine0(alloc, peerHost, peerPort);
+- /**
+- * Returns the number of sessions proposed by clients and either found in the internal or external session cache
+- * in server mode, but that were invalid due to timeout. These sessions are not included in the {@link #hits()}
+- * count.
+- */
+- public long timeouts() {
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- try {
+- return SSLContext.sessionTimeouts(context.ctx);
+- } finally {
+- readerLock.unlock();
+- }
- }
-
-- SSLEngine newEngine0(ByteBufAllocator alloc, String peerHost, int peerPort) {
-- return new ReferenceCountedOpenSslEngine(this, alloc, peerHost, peerPort, true);
+- /**
+- * Returns the number of sessions that were removed because the maximum session cache size was exceeded.
+- */
+- public long cacheFull() {
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- try {
+- return SSLContext.sessionCacheFull(context.ctx);
+- } finally {
+- readerLock.unlock();
+- }
- }
-
-- abstract OpenSslKeyMaterialManager keyMaterialManager();
+- /**
+- * Returns the number of times a client presented a ticket that did not match any key in the list.
+- */
+- public long ticketKeyFail() {
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- try {
+- return SSLContext.sessionTicketKeyFail(context.ctx);
+- } finally {
+- readerLock.unlock();
+- }
+- }
-
- /**
-- * Returns a new server-side {@link SSLEngine} with the current configuration.
+- * Returns the number of times a client did not present a ticket and we issued a new one
- */
-- @Override
-- public final SSLEngine newEngine(ByteBufAllocator alloc) {
-- return newEngine(alloc, null, -1);
+- public long ticketKeyNew() {
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- try {
+- return SSLContext.sessionTicketKeyNew(context.ctx);
+- } finally {
+- readerLock.unlock();
+- }
- }
-
- /**
-- * Returns the pointer to the {@code SSL_CTX} object for this {@link ReferenceCountedOpenSslContext}.
-- * Be aware that it is freed as soon as the {@link #finalize()} method is called.
-- * At this point {@code 0} will be returned.
-- *
-- * @deprecated this method is considered unsafe as the returned pointer may be released later. Dont use it!
+- * Returns the number of times a client presented a ticket derived from an older key,
+- * and we upgraded to the primary key.
- */
-- @Deprecated
-- public final long context() {
-- Lock readerLock = ctxLock.readLock();
+- public long ticketKeyRenew() {
+- Lock readerLock = context.ctxLock.readLock();
- readerLock.lock();
- try {
-- return ctx;
+- return SSLContext.sessionTicketKeyRenew(context.ctx);
- } finally {
- readerLock.unlock();
- }
- }
-
- /**
-- * Returns the stats of this context.
-- *
-- * @deprecated use {@link #sessionContext#stats()}
+- * Returns the number of times a client presented a ticket derived from the primary key.
- */
-- @Deprecated
-- public final OpenSslSessionStats stats() {
-- return sessionContext().stats();
+- public long ticketKeyResume() {
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- try {
+- return SSLContext.sessionTicketKeyResume(context.ctx);
+- } finally {
+- readerLock.unlock();
+- }
- }
+-}
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionTicketKey.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionTicketKey.java
+deleted file mode 100644
+index 79f71a65a3..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslSessionTicketKey.java
++++ /dev/null
+@@ -1,78 +0,0 @@
+-/*
+- * Copyright 2015 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- * http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-package io.netty.handler.ssl;
+-
+-import io.netty.internal.tcnative.SessionTicketKey;
+-
+-/**
+- * Session Ticket Key
+- */
+-public final class OpenSslSessionTicketKey {
-
- /**
-- * Specify if remote initiated renegotiation is supported or not. If not supported and the remote side tries
-- * to initiate a renegotiation a {@link SSLHandshakeException} will be thrown during decoding.
+- * Size of session ticket key name
+- */
+- public static final int NAME_SIZE = SessionTicketKey.NAME_SIZE;
+- /**
+- * Size of session ticket key HMAC key
+- */
+- public static final int HMAC_KEY_SIZE = SessionTicketKey.HMAC_KEY_SIZE;
+- /**
+- * Size of session ticket key AES key
- */
-- public void setRejectRemoteInitiatedRenegotiation(boolean rejectRemoteInitiatedRenegotiation) {
-- this.rejectRemoteInitiatedRenegotiation = rejectRemoteInitiatedRenegotiation;
-- }
--
+- public static final int AES_KEY_SIZE = SessionTicketKey.AES_KEY_SIZE;
- /**
-- * Returns if remote initiated renegotiation is supported or not.
+- * Size of session ticker key
- */
-- public boolean getRejectRemoteInitiatedRenegotiation() {
-- return rejectRemoteInitiatedRenegotiation;
-- }
+- public static final int TICKET_KEY_SIZE = SessionTicketKey.TICKET_KEY_SIZE;
+-
+- final SessionTicketKey key;
-
- /**
-- * Set the size of the buffer used by the BIO for non-application based writes
-- * (e.g. handshake, renegotiation, etc...).
+- * Construct a OpenSslSessionTicketKey.
+- *
+- * @param name the name of the session ticket key
+- * @param hmacKey the HMAC key of the session ticket key
+- * @param aesKey the AES key of the session ticket key
- */
-- public void setBioNonApplicationBufferSize(int bioNonApplicationBufferSize) {
-- this.bioNonApplicationBufferSize =
-- checkPositiveOrZero(bioNonApplicationBufferSize, "bioNonApplicationBufferSize");
+- public OpenSslSessionTicketKey(byte[] name, byte[] hmacKey, byte[] aesKey) {
+- key = new SessionTicketKey(name.clone(), hmacKey.clone(), aesKey.clone());
- }
-
- /**
-- * Returns the size of the buffer used by the BIO for non-application based writes
+- * Get name.
+- * @return the name of the session ticket key
- */
-- public int getBioNonApplicationBufferSize() {
-- return bioNonApplicationBufferSize;
+- public byte[] name() {
+- return key.getName().clone();
- }
-
- /**
-- * Sets the SSL session ticket keys of this context.
-- *
-- * @deprecated use {@link OpenSslSessionContext#setTicketKeys(byte[])}
+- * Get HMAC key.
+- * @return the HMAC key of the session ticket key
- */
-- @Deprecated
-- public final void setTicketKeys(byte[] keys) {
-- sessionContext().setTicketKeys(keys);
+- public byte[] hmacKey() {
+- return key.getHmacKey().clone();
- }
-
-- @Override
-- public abstract OpenSslSessionContext sessionContext();
--
- /**
-- * Returns the pointer to the {@code SSL_CTX} object for this {@link ReferenceCountedOpenSslContext}.
-- * Be aware that it is freed as soon as the {@link #release()} method is called.
-- * At this point {@code 0} will be returned.
-- *
-- * @deprecated this method is considered unsafe as the returned pointer may be released later. Dont use it!
+- * Get AES Key.
+- * @return the AES key of the session ticket key
- */
-- @Deprecated
-- public final long sslCtxPointer() {
-- Lock readerLock = ctxLock.readLock();
-- readerLock.lock();
-- try {
-- return ctx;
-- } finally {
-- readerLock.unlock();
-- }
+- public byte[] aesKey() {
+- return key.getAesKey().clone();
- }
+-}
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslTlsv13X509ExtendedTrustManager.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslTlsv13X509ExtendedTrustManager.java
+deleted file mode 100644
+index a5a84f2793..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslTlsv13X509ExtendedTrustManager.java
++++ /dev/null
+@@ -1,240 +0,0 @@
+-/*
+- * Copyright 2018 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- * http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-package io.netty.handler.ssl;
-
-- // IMPORTANT: This method must only be called from either the constructor or the finalizer as a user MUST never
-- // get access to an OpenSslSessionContext after this method was called to prevent the user from
-- // producing a segfault.
-- private void destroy() {
-- Lock writerLock = ctxLock.writeLock();
-- writerLock.lock();
-- try {
-- if (ctx != 0) {
-- if (enableOcsp) {
-- SSLContext.disableOcsp(ctx);
-- }
+-import io.netty.util.internal.PlatformDependent;
+-import io.netty.util.internal.SuppressJava6Requirement;
-
-- SSLContext.free(ctx);
-- ctx = 0;
-- }
-- } finally {
-- writerLock.unlock();
-- }
-- }
+-import javax.net.ssl.SSLEngine;
+-import javax.net.ssl.SSLPeerUnverifiedException;
+-import javax.net.ssl.SSLSession;
+-import javax.net.ssl.SSLSessionContext;
+-import javax.net.ssl.X509ExtendedTrustManager;
+-import java.net.Socket;
+-import java.security.Principal;
+-import java.security.cert.Certificate;
+-import java.security.cert.CertificateException;
+-import java.security.cert.X509Certificate;
+-import java.util.List;
-
-- protected static X509Certificate[] certificates(byte[][] chain) {
-- X509Certificate[] peerCerts = new X509Certificate[chain.length];
-- for (int i = 0; i < peerCerts.length; i++) {
-- peerCerts[i] = new OpenSslX509Certificate(chain[i]);
-- }
-- return peerCerts;
-- }
+-/**
+- * Provide a way to use {@code TLSv1.3} with Java versions prior to 11 by adding a
+- * <a href="http://mail.openjdk.java.net/pipermail/security-dev/2018-September/018242...>workaround</a> for the
+- * default {@link X509ExtendedTrustManager} implementations provided by the JDK that can not handle a protocol version
+- * of {@code TLSv1.3}.
+- */
+-@SuppressJava6Requirement(reason = "Usage guarded by java version check")
+-final class OpenSslTlsv13X509ExtendedTrustManager extends X509ExtendedTrustManager {
-
-- protected static X509TrustManager chooseTrustManager(TrustManager[] managers) {
-- for (TrustManager m : managers) {
-- if (m instanceof X509TrustManager) {
-- return (X509TrustManager) m;
-- }
-- }
-- throw new IllegalStateException("no X509TrustManager found");
-- }
+- private final X509ExtendedTrustManager tm;
-
-- protected static X509KeyManager chooseX509KeyManager(KeyManager[] kms) {
-- for (KeyManager km : kms) {
-- if (km instanceof X509KeyManager) {
-- return (X509KeyManager) km;
-- }
-- }
-- throw new IllegalStateException("no X509KeyManager found");
+- private OpenSslTlsv13X509ExtendedTrustManager(X509ExtendedTrustManager tm) {
+- this.tm = tm;
- }
-
-- /**
-- * Translate a {@link ApplicationProtocolConfig} object to a
-- * {@link OpenSslApplicationProtocolNegotiator} object.
-- *
-- * @param config The configuration which defines the translation
-- * @return The results of the translation
-- */
-- static OpenSslApplicationProtocolNegotiator toNegotiator(ApplicationProtocolConfig config) {
-- if (config == null) {
-- return NONE_PROTOCOL_NEGOTIATOR;
-- }
--
-- switch (config.protocol()) {
-- case NONE:
-- return NONE_PROTOCOL_NEGOTIATOR;
-- case ALPN:
-- case NPN:
-- case NPN_AND_ALPN:
-- switch (config.selectedListenerFailureBehavior()) {
-- case CHOOSE_MY_LAST_PROTOCOL:
-- case ACCEPT:
-- switch (config.selectorFailureBehavior()) {
-- case CHOOSE_MY_LAST_PROTOCOL:
-- case NO_ADVERTISE:
-- return new OpenSslDefaultApplicationProtocolNegotiator(
-- config);
-- default:
-- throw new UnsupportedOperationException(
-- new StringBuilder("OpenSSL provider does not support ")
-- .append(config.selectorFailureBehavior())
-- .append(" behavior").toString());
-- }
-- default:
-- throw new UnsupportedOperationException(
-- new StringBuilder("OpenSSL provider does not support ")
-- .append(config.selectedListenerFailureBehavior())
-- .append(" behavior").toString());
-- }
-- default:
-- throw new Error();
+- static X509ExtendedTrustManager wrap(X509ExtendedTrustManager tm) {
+- if (PlatformDependent.javaVersion() < 11 && OpenSsl.isTlsv13Supported()) {
+- return new OpenSslTlsv13X509ExtendedTrustManager(tm);
- }
-- }
--
-- static boolean useExtendedTrustManager(X509TrustManager trustManager) {
-- return PlatformDependent.javaVersion() >= 7 && trustManager instanceof X509ExtendedTrustManager;
-- }
--
-- static boolean useExtendedKeyManager(X509KeyManager keyManager) {
-- return PlatformDependent.javaVersion() >= 7 && keyManager instanceof X509ExtendedKeyManager;
-- }
--
-- @Override
-- public final int refCnt() {
-- return refCnt.refCnt();
+- return tm;
- }
-
- @Override
-- public final ReferenceCounted retain() {
-- refCnt.retain();
-- return this;
-- }
--
-- @Override
-- public final ReferenceCounted retain(int increment) {
-- refCnt.retain(increment);
-- return this;
+- public void checkClientTrusted(X509Certificate[] x509Certificates, String s, Socket socket)
+- throws CertificateException {
+- tm.checkClientTrusted(x509Certificates, s, socket);
- }
-
- @Override
-- public final ReferenceCounted touch() {
-- refCnt.touch();
-- return this;
+- public void checkServerTrusted(X509Certificate[] x509Certificates, String s, Socket socket)
+- throws CertificateException {
+- tm.checkServerTrusted(x509Certificates, s, socket);
- }
-
-- @Override
-- public final ReferenceCounted touch(Object hint) {
-- refCnt.touch(hint);
-- return this;
-- }
+- private static SSLEngine wrapEngine(final SSLEngine engine) {
+- final SSLSession session = engine.getHandshakeSession();
+- if (session != null && SslUtils.PROTOCOL_TLS_V1_3.equals(session.getProtocol())) {
+- return new JdkSslEngine(engine) {
+- @Override
+- public String getNegotiatedApplicationProtocol() {
+- if (engine instanceof ApplicationProtocolAccessor) {
+- return ((ApplicationProtocolAccessor) engine).getNegotiatedApplicationProtocol();
+- }
+- return super.getNegotiatedApplicationProtocol();
+- }
-
-- @Override
-- public final boolean release() {
-- return refCnt.release();
-- }
+- @Override
+- public SSLSession getHandshakeSession() {
+- if (PlatformDependent.javaVersion() >= 7 && session instanceof ExtendedOpenSslSession) {
+- final ExtendedOpenSslSession extendedOpenSslSession = (ExtendedOpenSslSession) session;
+- return new ExtendedOpenSslSession(extendedOpenSslSession) {
+- @Override
+- public List getRequestedServerNames() {
+- return extendedOpenSslSession.getRequestedServerNames();
+- }
-
-- @Override
-- public final boolean release(int decrement) {
-- return refCnt.release(decrement);
-- }
+- @Override
+- public String[] getPeerSupportedSignatureAlgorithms() {
+- return extendedOpenSslSession.getPeerSupportedSignatureAlgorithms();
+- }
-
-- abstract static class AbstractCertificateVerifier extends CertificateVerifier {
-- private final OpenSslEngineMap engineMap;
+- @Override
+- public String getProtocol() {
+- return SslUtils.PROTOCOL_TLS_V1_2;
+- }
+- };
+- } else {
+- return new SSLSession() {
+- @Override
+- public byte[] getId() {
+- return session.getId();
+- }
-
-- AbstractCertificateVerifier(OpenSslEngineMap engineMap) {
-- this.engineMap = engineMap;
-- }
+- @Override
+- public SSLSessionContext getSessionContext() {
+- return session.getSessionContext();
+- }
-
-- @Override
-- public final int verify(long ssl, byte[][] chain, String auth) {
-- X509Certificate[] peerCerts = certificates(chain);
-- final ReferenceCountedOpenSslEngine engine = engineMap.get(ssl);
-- try {
-- verify(engine, peerCerts, auth);
-- return CertificateVerifier.X509_V_OK;
-- } catch (Throwable cause) {
-- logger.debug("verification of certificate failed", cause);
-- SSLHandshakeException e = new SSLHandshakeException("General OpenSslEngine problem");
-- e.initCause(cause);
-- engine.handshakeException = e;
+- @Override
+- public long getCreationTime() {
+- return session.getCreationTime();
+- }
-
-- // Try to extract the correct error code that should be used.
-- if (cause instanceof OpenSslCertificateException) {
-- // This will never return a negative error code as its validated when constructing the
-- // OpenSslCertificateException.
-- return ((OpenSslCertificateException) cause).errorCode();
-- }
-- if (cause instanceof CertificateExpiredException) {
-- return CertificateVerifier.X509_V_ERR_CERT_HAS_EXPIRED;
-- }
-- if (cause instanceof CertificateNotYetValidException) {
-- return CertificateVerifier.X509_V_ERR_CERT_NOT_YET_VALID;
-- }
-- if (PlatformDependent.javaVersion() >= 7) {
-- if (cause instanceof CertificateRevokedException) {
-- return CertificateVerifier.X509_V_ERR_CERT_REVOKED;
-- }
+- @Override
+- public long getLastAccessedTime() {
+- return session.getLastAccessedTime();
+- }
-
-- // The X509TrustManagerImpl uses a Validator which wraps a CertPathValidatorException into
-- // an CertificateException. So we need to handle the wrapped CertPathValidatorException to be
-- // able to send the correct alert.
-- Throwable wrapped = cause.getCause();
-- while (wrapped != null) {
-- if (wrapped instanceof CertPathValidatorException) {
-- CertPathValidatorException ex = (CertPathValidatorException) wrapped;
-- CertPathValidatorException.Reason reason = ex.getReason();
-- if (reason == CertPathValidatorException.BasicReason.EXPIRED) {
-- return CertificateVerifier.X509_V_ERR_CERT_HAS_EXPIRED;
+- @Override
+- public void invalidate() {
+- session.invalidate();
- }
-- if (reason == CertPathValidatorException.BasicReason.NOT_YET_VALID) {
-- return CertificateVerifier.X509_V_ERR_CERT_NOT_YET_VALID;
+-
+- @Override
+- public boolean isValid() {
+- return session.isValid();
- }
-- if (reason == CertPathValidatorException.BasicReason.REVOKED) {
-- return CertificateVerifier.X509_V_ERR_CERT_REVOKED;
+-
+- @Override
+- public void putValue(String s, Object o) {
+- session.putValue(s, o);
- }
-- }
-- wrapped = wrapped.getCause();
-- }
-- }
-
-- // Could not detect a specific error code to use, so fallback to a default code.
-- return CertificateVerifier.X509_V_ERR_UNSPECIFIED;
-- }
-- }
+- @Override
+- public Object getValue(String s) {
+- return session.getValue(s);
+- }
-
-- abstract void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts,
-- String auth) throws Exception;
-- }
+- @Override
+- public void removeValue(String s) {
+- session.removeValue(s);
+- }
-
-- private static final class DefaultOpenSslEngineMap implements OpenSslEngineMap {
-- private final Map<Long, ReferenceCountedOpenSslEngine> engines = PlatformDependent.newConcurrentHashMap();
+- @Override
+- public String[] getValueNames() {
+- return session.getValueNames();
+- }
-
-- @Override
-- public ReferenceCountedOpenSslEngine remove(long ssl) {
-- return engines.remove(ssl);
-- }
+- @Override
+- public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException {
+- return session.getPeerCertificates();
+- }
-
-- @Override
-- public void add(ReferenceCountedOpenSslEngine engine) {
-- engines.put(engine.sslPointer(), engine);
-- }
+- @Override
+- public Certificate[] getLocalCertificates() {
+- return session.getLocalCertificates();
+- }
-
-- @Override
-- public ReferenceCountedOpenSslEngine get(long ssl) {
-- return engines.get(ssl);
-- }
-- }
+- @Override
+- public javax.security.cert.X509Certificate[] getPeerCertificateChain()
+- throws SSLPeerUnverifiedException {
+- return session.getPeerCertificateChain();
+- }
-
-- static void setKeyMaterial(long ctx, X509Certificate[] keyCertChain, PrivateKey key, String keyPassword)
-- throws SSLException {
-- /* Load the certificate file and private key. */
-- long keyBio = 0;
-- long keyCertChainBio = 0;
-- long keyCertChainBio2 = 0;
-- PemEncoded encoded = null;
-- try {
-- // Only encode one time
-- encoded = PemX509Certificate.toPEM(ByteBufAllocator.DEFAULT, true, keyCertChain);
-- keyCertChainBio = toBIO(ByteBufAllocator.DEFAULT, encoded.retain());
-- keyCertChainBio2 = toBIO(ByteBufAllocator.DEFAULT, encoded.retain());
+- @Override
+- public Principal getPeerPrincipal() throws SSLPeerUnverifiedException {
+- return session.getPeerPrincipal();
+- }
-
-- if (key != null) {
-- keyBio = toBIO(key);
-- }
+- @Override
+- public Principal getLocalPrincipal() {
+- return session.getLocalPrincipal();
+- }
-
-- SSLContext.setCertificateBio(
-- ctx, keyCertChainBio, keyBio,
-- keyPassword == null ? StringUtil.EMPTY_STRING : keyPassword);
-- // We may have more then one cert in the chain so add all of them now.
-- SSLContext.setCertificateChainBio(ctx, keyCertChainBio2, true);
-- } catch (SSLException e) {
-- throw e;
-- } catch (Exception e) {
-- throw new SSLException("failed to set certificate and key", e);
-- } finally {
-- freeBio(keyBio);
-- freeBio(keyCertChainBio);
-- freeBio(keyCertChainBio2);
-- if (encoded != null) {
-- encoded.release();
-- }
-- }
-- }
+- @Override
+- public String getCipherSuite() {
+- return session.getCipherSuite();
+- }
-
-- static void freeBio(long bio) {
-- if (bio != 0) {
-- SSL.freeBIO(bio);
-- }
-- }
+- @Override
+- public String getProtocol() {
+- return SslUtils.PROTOCOL_TLS_V1_2;
+- }
-
-- /**
-- * Return the pointer to a <a href="https://www.openssl.org/docs/crypto/BIO_get_mem_ptr.html">in-memory BIO</a>
-- * or {@code 0} if the {@code key} is {@code null}. The BIO contains the content of the {@code key}.
-- */
-- static long toBIO(PrivateKey key) throws Exception {
-- if (key == null) {
-- return 0;
-- }
+- @Override
+- public String getPeerHost() {
+- return session.getPeerHost();
+- }
-
-- ByteBufAllocator allocator = ByteBufAllocator.DEFAULT;
-- PemEncoded pem = PemPrivateKey.toPEM(allocator, true, key);
-- try {
-- return toBIO(allocator, pem.retain());
-- } finally {
-- pem.release();
-- }
-- }
+- @Override
+- public int getPeerPort() {
+- return session.getPeerPort();
+- }
-
-- /**
-- * Return the pointer to a <a href="https://www.openssl.org/docs/crypto/BIO_get_mem_ptr.html">in-memory BIO</a>
-- * or {@code 0} if the {@code certChain} is {@code null}. The BIO contains the content of the {@code certChain}.
-- */
-- static long toBIO(X509Certificate... certChain) throws Exception {
-- if (certChain == null) {
-- return 0;
-- }
+- @Override
+- public int getPacketBufferSize() {
+- return session.getPacketBufferSize();
+- }
-
-- if (certChain.length == 0) {
-- throw new IllegalArgumentException("certChain can't be empty");
+- @Override
+- public int getApplicationBufferSize() {
+- return session.getApplicationBufferSize();
+- }
+- };
+- }
+- }
+- };
- }
+- return engine;
+- }
-
-- ByteBufAllocator allocator = ByteBufAllocator.DEFAULT;
-- PemEncoded pem = PemX509Certificate.toPEM(allocator, true, certChain);
-- try {
-- return toBIO(allocator, pem.retain());
-- } finally {
-- pem.release();
-- }
+- @Override
+- public void checkClientTrusted(X509Certificate[] x509Certificates, final String s, SSLEngine sslEngine)
+- throws CertificateException {
+- tm.checkClientTrusted(x509Certificates, s, wrapEngine(sslEngine));
- }
-
-- static long toBIO(ByteBufAllocator allocator, PemEncoded pem) throws Exception {
-- try {
-- // We can turn direct buffers straight into BIOs. No need to
-- // make a yet another copy.
-- ByteBuf content = pem.content();
+- @Override
+- public void checkServerTrusted(X509Certificate[] x509Certificates, String s, SSLEngine sslEngine)
+- throws CertificateException {
+- tm.checkServerTrusted(x509Certificates, s, wrapEngine(sslEngine));
+- }
-
-- if (content.isDirect()) {
-- return newBIO(content.retainedSlice());
-- }
+- @Override
+- public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
+- tm.checkClientTrusted(x509Certificates, s);
+- }
-
-- ByteBuf buffer = allocator.directBuffer(content.readableBytes());
-- try {
-- buffer.writeBytes(content, content.readerIndex(), content.readableBytes());
-- return newBIO(buffer.retainedSlice());
-- } finally {
-- try {
-- // If the contents of the ByteBuf is sensitive (e.g. a PrivateKey) we
-- // need to zero out the bytes of the copy before we're releasing it.
-- if (pem.isSensitive()) {
-- SslUtils.zeroout(buffer);
-- }
-- } finally {
-- buffer.release();
-- }
-- }
-- } finally {
-- pem.release();
-- }
+- @Override
+- public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
+- tm.checkServerTrusted(x509Certificates, s);
- }
-
-- private static long newBIO(ByteBuf buffer) throws Exception {
-- try {
-- long bio = SSL.newMemBIO();
-- int readable = buffer.readableBytes();
-- if (SSL.bioWrite(bio, OpenSsl.memoryAddress(buffer) + buffer.readerIndex(), readable) != readable) {
-- SSL.freeBIO(bio);
-- throw new IllegalStateException("Could not write data to memory BIO");
-- }
-- return bio;
-- } finally {
-- buffer.release();
-- }
+- @Override
+- public X509Certificate[] getAcceptedIssuers() {
+- return tm.getAcceptedIssuers();
- }
-}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngine.java b/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngine.java
+diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslX509KeyManagerFactory.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslX509KeyManagerFactory.java
deleted file mode 100644
-index 27460c7..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngine.java
+index 2a86332fe1..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/OpenSslX509KeyManagerFactory.java
+++ /dev/null
-@@ -1,2037 +0,0 @@
+@@ -1,413 +0,0 @@
-/*
-- * Copyright 2016 The Netty Project
+- * Copyright 2018 The Netty Project
- *
- * The Netty Project licenses this file to you under the Apache License,
- * version 2.0 (the "License"); you may not use this file except in compliance
@@ -3485,4638 +3793,4204 @@ index 27460c7..0000000
- */
-package io.netty.handler.ssl;
-
--import io.netty.buffer.ByteBuf;
-import io.netty.buffer.ByteBufAllocator;
--import io.netty.internal.tcnative.Buffer;
+-import io.netty.buffer.UnpooledByteBufAllocator;
-import io.netty.internal.tcnative.SSL;
--import io.netty.util.AbstractReferenceCounted;
--import io.netty.util.ReferenceCounted;
--import io.netty.util.ResourceLeakDetector;
--import io.netty.util.ResourceLeakDetectorFactory;
--import io.netty.util.ResourceLeakTracker;
--import io.netty.util.internal.EmptyArrays;
--import io.netty.util.internal.PlatformDependent;
--import io.netty.util.internal.StringUtil;
--import io.netty.util.internal.ThrowableUtil;
--import io.netty.util.internal.UnstableApi;
--import io.netty.util.internal.logging.InternalLogger;
--import io.netty.util.internal.logging.InternalLoggerFactory;
+-import io.netty.util.ReferenceCountUtil;
+-import io.netty.util.internal.ObjectUtil;
-
--import java.nio.ByteBuffer;
--import java.nio.ReadOnlyBufferException;
--import java.security.Principal;
+-import javax.net.ssl.KeyManager;
+-import javax.net.ssl.KeyManagerFactory;
+-import javax.net.ssl.KeyManagerFactorySpi;
+-import javax.net.ssl.ManagerFactoryParameters;
+-import javax.net.ssl.X509KeyManager;
+-import java.io.File;
+-import java.io.IOException;
+-import java.io.InputStream;
+-import java.io.OutputStream;
+-import java.security.InvalidAlgorithmParameterException;
+-import java.security.Key;
+-import java.security.KeyStore;
+-import java.security.KeyStoreException;
+-import java.security.KeyStoreSpi;
+-import java.security.NoSuchAlgorithmException;
+-import java.security.PrivateKey;
+-import java.security.Provider;
+-import java.security.UnrecoverableKeyException;
-import java.security.cert.Certificate;
--import java.util.ArrayList;
--import java.util.Arrays;
--import java.util.Collection;
+-import java.security.cert.CertificateException;
+-import java.security.cert.X509Certificate;
+-import java.util.Collections;
+-import java.util.Date;
+-import java.util.Enumeration;
-import java.util.HashMap;
--import java.util.List;
-import java.util.Map;
--import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
--
--import java.util.concurrent.locks.Lock;
--import javax.net.ssl.SSLEngine;
--import javax.net.ssl.SSLEngineResult;
--import javax.net.ssl.SSLException;
--import javax.net.ssl.SSLHandshakeException;
--import javax.net.ssl.SSLParameters;
--import javax.net.ssl.SSLPeerUnverifiedException;
--import javax.net.ssl.SSLSession;
--import javax.net.ssl.SSLSessionBindingEvent;
--import javax.net.ssl.SSLSessionBindingListener;
--import javax.net.ssl.SSLSessionContext;
--import javax.security.cert.X509Certificate;
--
--import static io.netty.handler.ssl.OpenSsl.memoryAddress;
--import static io.netty.handler.ssl.SslUtils.SSL_RECORD_HEADER_LENGTH;
--import static io.netty.util.internal.EmptyArrays.EMPTY_CERTIFICATES;
--import static io.netty.util.internal.EmptyArrays.EMPTY_JAVAX_X509_CERTIFICATES;
--import static io.netty.util.internal.ObjectUtil.checkNotNull;
--import static java.lang.Math.min;
--import static javax.net.ssl.SSLEngineResult.HandshakeStatus.FINISHED;
--import static javax.net.ssl.SSLEngineResult.HandshakeStatus.NEED_UNWRAP;
--import static javax.net.ssl.SSLEngineResult.HandshakeStatus.NEED_WRAP;
--import static javax.net.ssl.SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING;
--import static javax.net.ssl.SSLEngineResult.Status.BUFFER_OVERFLOW;
--import static javax.net.ssl.SSLEngineResult.Status.BUFFER_UNDERFLOW;
--import static javax.net.ssl.SSLEngineResult.Status.CLOSED;
--import static javax.net.ssl.SSLEngineResult.Status.OK;
-
-/**
-- * Implements a {@link SSLEngine} using
-- * <a href="https://www.openssl.org/docs/crypto/BIO_s_bio.html#EXAMPLE">OpenSSL BIO abstractions</a>.
-- * <p>Instances of this class must be {@link #release() released} or else native memory will leak!
+- * Special {@link KeyManagerFactory} that pre-compute the keymaterial used when {@link SslProvider#OPENSSL} or
+- * {@link SslProvider#OPENSSL_REFCNT} is used and so will improve handshake times and its performance.
- *
-- * <p>Instances of this class <strong>must</strong> be released before the {@link ReferenceCountedOpenSslContext}
-- * the instance depends upon are released. Otherwise if any method of this class is called which uses the
-- * the {@link ReferenceCountedOpenSslContext} JNI resources the JVM may crash.
-- */
--public class ReferenceCountedOpenSslEngine extends SSLEngine implements ReferenceCounted {
--
-- private static final InternalLogger logger = InternalLoggerFactory.getInstance(ReferenceCountedOpenSslEngine.class);
--
-- private static final SSLException BEGIN_HANDSHAKE_ENGINE_CLOSED = ThrowableUtil.unknownStackTrace(
-- new SSLException("engine closed"), ReferenceCountedOpenSslEngine.class, "beginHandshake()");
-- private static final SSLException HANDSHAKE_ENGINE_CLOSED = ThrowableUtil.unknownStackTrace(
-- new SSLException("engine closed"), ReferenceCountedOpenSslEngine.class, "handshake()");
-- private static final SSLException RENEGOTIATION_UNSUPPORTED = ThrowableUtil.unknownStackTrace(
-- new SSLException("renegotiation unsupported"), ReferenceCountedOpenSslEngine.class, "beginHandshake()");
-- private static final ResourceLeakDetector<ReferenceCountedOpenSslEngine> leakDetector =
-- ResourceLeakDetectorFactory.instance().newResourceLeakDetector(ReferenceCountedOpenSslEngine.class);
-- /**
-- * <a href="https://www.openssl.org/docs/man1.0.2/crypto/X509_check_host.html">The flags argument is usually 0</a>.
-- */
-- private static final int DEFAULT_HOSTNAME_VALIDATION_FLAGS = 0;
+- *
+- *
+- * Because the keymaterial is pre-computed any modification to the {@link KeyStore} is ignored after
+- * {@link #init(KeyStore, char[])} is called.
+- *
+- * {@link #init(ManagerFactoryParameters)} is not supported by this implementation and so a call to it will always
+- * result in an {@link InvalidAlgorithmParameterException}.
+- */
+-public final class OpenSslX509KeyManagerFactory extends KeyManagerFactory {
-
-- static final int MAX_PLAINTEXT_LENGTH = 16 * 1024; // 2^14
+- private final OpenSslKeyManagerFactorySpi spi;
-
-- /**
-- * This is the maximum overhead when encrypting plaintext as defined by
-- * <a href="https://www.ietf.org/rfc/rfc5246.txt">rfc5264</a>,
-- * <a href="https://www.ietf.org/rfc/rfc5289.txt">rfc5289</a> and openssl implementation itself.
-- *
-- * Please note that we use a padding of 16 here as openssl uses PKC#5 which uses 16 bytes while the spec itself
-- * allow up to 255 bytes. 16 bytes is the max for PKC#5 (which handles it the same way as PKC#7) as we use a block
-- * size of 16. See <a href="https://tools.ietf.org/html/rfc5652#section-6.3">rfc5652#section-6.3</a>.
-- *
-- * TLS Header (5) + 16 (IV) + 48 (MAC) + 1 (Padding_length field) + 15 (Padding) + 1 (ContentType) +
-- * 2 (ProtocolVersion) + 2 (Length)
-- *
-- * TODO: We may need to review this calculation once TLS 1.3 becomes available.
-- */
-- static final int MAX_TLS_RECORD_OVERHEAD_LENGTH = SSL_RECORD_HEADER_LENGTH + 16 + 48 + 1 + 15 + 1 + 2 + 2;
+- public OpenSslX509KeyManagerFactory() {
+- this(newOpenSslKeyManagerFactorySpi(null));
+- }
-
-- static final int MAX_ENCRYPTED_PACKET_LENGTH = MAX_PLAINTEXT_LENGTH + MAX_TLS_RECORD_OVERHEAD_LENGTH;
+- public OpenSslX509KeyManagerFactory(Provider provider) {
+- this(newOpenSslKeyManagerFactorySpi(provider));
+- }
-
-- private static final AtomicIntegerFieldUpdater<ReferenceCountedOpenSslEngine> DESTROYED_UPDATER =
-- AtomicIntegerFieldUpdater.newUpdater(ReferenceCountedOpenSslEngine.class, "destroyed");
+- public OpenSslX509KeyManagerFactory(String algorithm, Provider provider) throws NoSuchAlgorithmException {
+- this(newOpenSslKeyManagerFactorySpi(algorithm, provider));
+- }
-
-- private static final String INVALID_CIPHER = "SSL_NULL_WITH_NULL_NULL";
-- private static final SSLEngineResult NEED_UNWRAP_OK = new SSLEngineResult(OK, NEED_UNWRAP, 0, 0);
-- private static final SSLEngineResult NEED_UNWRAP_CLOSED = new SSLEngineResult(CLOSED, NEED_UNWRAP, 0, 0);
-- private static final SSLEngineResult NEED_WRAP_OK = new SSLEngineResult(OK, NEED_WRAP, 0, 0);
-- private static final SSLEngineResult NEED_WRAP_CLOSED = new SSLEngineResult(CLOSED, NEED_WRAP, 0, 0);
-- private static final SSLEngineResult CLOSED_NOT_HANDSHAKING = new SSLEngineResult(CLOSED, NOT_HANDSHAKING, 0, 0);
+- private OpenSslX509KeyManagerFactory(OpenSslKeyManagerFactorySpi spi) {
+- super(spi, spi.kmf.getProvider(), spi.kmf.getAlgorithm());
+- this.spi = spi;
+- }
-
-- // OpenSSL state
-- private long ssl;
-- private long networkBIO;
-- private boolean certificateSet;
+- private static OpenSslKeyManagerFactorySpi newOpenSslKeyManagerFactorySpi(Provider provider) {
+- try {
+- return newOpenSslKeyManagerFactorySpi(null, provider);
+- } catch (NoSuchAlgorithmException e) {
+- // This should never happen as we use the default algorithm.
+- throw new IllegalStateException(e);
+- }
+- }
-
-- private enum HandshakeState {
-- /**
-- * Not started yet.
-- */
-- NOT_STARTED,
-- /**
-- * Started via unwrap/wrap.
-- */
-- STARTED_IMPLICITLY,
-- /**
-- * Started via {@link #beginHandshake()}.
-- */
-- STARTED_EXPLICITLY,
+- private static OpenSslKeyManagerFactorySpi newOpenSslKeyManagerFactorySpi(String algorithm, Provider provider)
+- throws NoSuchAlgorithmException {
+- if (algorithm == null) {
+- algorithm = KeyManagerFactory.getDefaultAlgorithm();
+- }
+- return new OpenSslKeyManagerFactorySpi(
+- provider == null ? KeyManagerFactory.getInstance(algorithm) :
+- KeyManagerFactory.getInstance(algorithm, provider));
+- }
-
-- /**
-- * Handshake is finished.
-- */
-- FINISHED
+- OpenSslKeyMaterialProvider newProvider() {
+- return spi.newProvider();
- }
-
-- private HandshakeState handshakeState = HandshakeState.NOT_STARTED;
-- private boolean renegotiationPending;
-- private boolean receivedShutdown;
-- private volatile int destroyed;
+- private static final class OpenSslKeyManagerFactorySpi extends KeyManagerFactorySpi {
+- final KeyManagerFactory kmf;
+- private volatile ProviderFactory providerFactory;
+-
+- OpenSslKeyManagerFactorySpi(KeyManagerFactory kmf) {
+- this.kmf = ObjectUtil.checkNotNull(kmf, "kmf");
+- }
-
-- // Reference Counting
-- private final ResourceLeakTracker<ReferenceCountedOpenSslEngine> leak;
-- private final AbstractReferenceCounted refCnt = new AbstractReferenceCounted() {
- @Override
-- public ReferenceCounted touch(Object hint) {
-- if (leak != null) {
-- leak.record(hint);
+- protected synchronized void engineInit(KeyStore keyStore, char[] chars)
+- throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
+- if (providerFactory != null) {
+- throw new KeyStoreException("Already initialized");
+- }
+- if (!keyStore.aliases().hasMoreElements()) {
+- throw new KeyStoreException("No aliases found");
- }
-
-- return ReferenceCountedOpenSslEngine.this;
+- kmf.init(keyStore, chars);
+- providerFactory = new ProviderFactory(ReferenceCountedOpenSslContext.chooseX509KeyManager(
+- kmf.getKeyManagers()), password(chars), Collections.list(keyStore.aliases()));
- }
-
-- @Override
-- protected void deallocate() {
-- shutdown();
-- if (leak != null) {
-- boolean closed = leak.close(ReferenceCountedOpenSslEngine.this);
-- assert closed;
+- private static String password(char[] password) {
+- if (password == null || password.length == 0) {
+- return null;
- }
+- return new String(password);
- }
-- };
-
-- private volatile ClientAuth clientAuth = ClientAuth.NONE;
+- @Override
+- protected void engineInit(ManagerFactoryParameters managerFactoryParameters)
+- throws InvalidAlgorithmParameterException {
+- throw new InvalidAlgorithmParameterException("Not supported");
+- }
-
-- // Updated once a new handshake is started and so the SSLSession reused.
-- private volatile long lastAccessed = -1;
+- @Override
+- protected KeyManager[] engineGetKeyManagers() {
+- ProviderFactory providerFactory = this.providerFactory;
+- if (providerFactory == null) {
+- throw new IllegalStateException("engineInit(...) not called yet");
+- }
+- return new KeyManager[] { providerFactory.keyManager };
+- }
-
-- private String endPointIdentificationAlgorithm;
-- // Store as object as AlgorithmConstraints only exists since java 7.
-- private Object algorithmConstraints;
-- private List<String> sniHostNames;
+- OpenSslKeyMaterialProvider newProvider() {
+- ProviderFactory providerFactory = this.providerFactory;
+- if (providerFactory == null) {
+- throw new IllegalStateException("engineInit(...) not called yet");
+- }
+- return providerFactory.newProvider();
+- }
-
-- // Mark as volatile as accessed by checkSniHostnameMatch(...) and also not specify the SNIMatcher type to allow us
-- // using it with java7.
-- private volatile Collection<?> matchers;
+- private static final class ProviderFactory {
+- private final X509KeyManager keyManager;
+- private final String password;
+- private final Iterable<String> aliases;
-
-- // SSL Engine status variables
-- private boolean isInboundDone;
-- private boolean outboundClosed;
+- ProviderFactory(X509KeyManager keyManager, String password, Iterable<String> aliases) {
+- this.keyManager = keyManager;
+- this.password = password;
+- this.aliases = aliases;
+- }
-
-- private final boolean clientMode;
-- private final ByteBufAllocator alloc;
-- private final OpenSslEngineMap engineMap;
-- private final OpenSslApplicationProtocolNegotiator apn;
-- private final boolean rejectRemoteInitiatedRenegotiation;
-- private final OpenSslSession session;
-- private final Certificate[] localCerts;
-- private final ByteBuffer[] singleSrcBuffer = new ByteBuffer[1];
-- private final ByteBuffer[] singleDstBuffer = new ByteBuffer[1];
-- private final OpenSslKeyMaterialManager keyMaterialManager;
-- private final boolean enableOcsp;
+- OpenSslKeyMaterialProvider newProvider() {
+- return new OpenSslPopulatedKeyMaterialProvider(keyManager,
+- password, aliases);
+- }
-
-- // This is package-private as we set it from OpenSslContext if an exception is thrown during
-- // the verification step.
-- SSLHandshakeException handshakeException;
+- /**
+- * {@link OpenSslKeyMaterialProvider} implementation that pre-compute the {@link OpenSslKeyMaterial} for
+- * all aliases.
+- */
+- private static final class OpenSslPopulatedKeyMaterialProvider extends OpenSslKeyMaterialProvider {
+- private final Map<String, Object> materialMap;
-
-- /**
-- * Create a new instance.
-- * @param context Reference count release responsibility is not transferred! The callee still owns this object.
-- * @param alloc The allocator to use.
-- * @param peerHost The peer host name.
-- * @param peerPort The peer port.
-- * @param leakDetection {@code true} to enable leak detection of this object.
-- */
-- ReferenceCountedOpenSslEngine(ReferenceCountedOpenSslContext context, ByteBufAllocator alloc, String peerHost,
-- int peerPort, boolean leakDetection) {
-- super(peerHost, peerPort);
-- OpenSsl.ensureAvailability();
-- leak = leakDetection ? leakDetector.track(this) : null;
-- this.alloc = checkNotNull(alloc, "alloc");
-- apn = (OpenSslApplicationProtocolNegotiator) context.applicationProtocolNegotiator();
-- session = new OpenSslSession(context.sessionContext());
-- clientMode = context.isClient();
-- engineMap = context.engineMap;
-- rejectRemoteInitiatedRenegotiation = context.getRejectRemoteInitiatedRenegotiation();
-- localCerts = context.keyCertChain;
-- keyMaterialManager = context.keyMaterialManager();
-- enableOcsp = context.enableOcsp;
+- OpenSslPopulatedKeyMaterialProvider(
+- X509KeyManager keyManager, String password, Iterable<String> aliases) {
+- super(keyManager, password);
+- materialMap = new HashMap<String, Object>();
+- boolean initComplete = false;
+- try {
+- for (String alias: aliases) {
+- if (alias != null && !materialMap.containsKey(alias)) {
+- try {
+- materialMap.put(alias, super.chooseKeyMaterial(
+- UnpooledByteBufAllocator.DEFAULT, alias));
+- } catch (Exception e) {
+- // Just store the exception and rethrow it when we try to choose the keymaterial
+- // for this alias later on.
+- materialMap.put(alias, e);
+- }
+- }
+- }
+- initComplete = true;
+- } finally {
+- if (!initComplete) {
+- destroy();
+- }
+- }
+- if (materialMap.isEmpty()) {
+- throw new IllegalArgumentException("aliases must be non-empty");
+- }
+- }
-
-- Lock readerLock = context.ctxLock.readLock();
-- readerLock.lock();
-- try {
-- ssl = SSL.newSSL(context.ctx, !context.isClient());
-- } finally {
-- readerLock.unlock();
+- @Override
+- OpenSslKeyMaterial chooseKeyMaterial(ByteBufAllocator allocator, String alias) throws Exception {
+- Object value = materialMap.get(alias);
+- if (value == null) {
+- // There is no keymaterial for the requested alias, return null
+- return null;
+- }
+- if (value instanceof OpenSslKeyMaterial) {
+- return ((OpenSslKeyMaterial) value).retain();
+- }
+- throw (Exception) value;
+- }
+-
+- @Override
+- void destroy() {
+- for (Object material: materialMap.values()) {
+- ReferenceCountUtil.release(material);
+- }
+- materialMap.clear();
+- }
+- }
- }
-- try {
-- networkBIO = SSL.bioNewByteBuffer(ssl, context.getBioNonApplicationBufferSize());
+- }
-
-- // Set the client auth mode, this needs to be done via setClientAuth(...) method so we actually call the
-- // needed JNI methods.
-- setClientAuth(clientMode ? ClientAuth.NONE : context.clientAuth);
+- /**
+- * Create a new initialized {@link OpenSslX509KeyManagerFactory} which loads its {@link PrivateKey} directly from
+- * an {@code OpenSSL engine} via the
+- * <a href="https://www.openssl.org/docs/man1.1.0/crypto/ENGINE_load_private_key.html">ENGINE_load_private_key</a>
+- * function.
+- */
+- public static OpenSslX509KeyManagerFactory newEngineBased(File certificateChain, String password)
+- throws CertificateException, IOException,
+- KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
+- return newEngineBased(SslContext.toX509Certificates(certificateChain), password);
+- }
-
-- if (context.protocols != null) {
-- setEnabledProtocols(context.protocols);
-- }
+- /**
+- * Create a new initialized {@link OpenSslX509KeyManagerFactory} which loads its {@link PrivateKey} directly from
+- * an {@code OpenSSL engine} via the
+- * <a href="https://www.openssl.org/docs/man1.1.0/crypto/ENGINE_load_private_key.html">ENGINE_load_private_key</a>
+- * function.
+- */
+- public static OpenSslX509KeyManagerFactory newEngineBased(X509Certificate[] certificateChain, String password)
+- throws CertificateException, IOException,
+- KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
+- KeyStore store = new OpenSslKeyStore(certificateChain.clone(), false);
+- store.load(null, null);
+- OpenSslX509KeyManagerFactory factory = new OpenSslX509KeyManagerFactory();
+- factory.init(store, password == null ? null : password.toCharArray());
+- return factory;
+- }
-
-- // Use SNI if peerHost was specified
-- // See https://github.com/netty/netty/issues/4746
-- if (clientMode && peerHost != null) {
-- SSL.setTlsExtHostName(ssl, peerHost);
-- }
+- /**
+- * See {@link OpenSslX509KeyManagerFactory#newEngineBased(X509Certificate[], String)}.
+- */
+- public static OpenSslX509KeyManagerFactory newKeyless(File chain)
+- throws CertificateException, IOException,
+- KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
+- return newKeyless(SslContext.toX509Certificates(chain));
+- }
-
-- if (enableOcsp) {
-- SSL.enableOcsp(ssl);
-- }
-- } catch (Throwable cause) {
-- SSL.freeSSL(ssl);
-- PlatformDependent.throwException(cause);
-- }
+- /**
+- * See {@link OpenSslX509KeyManagerFactory#newEngineBased(X509Certificate[], String)}.
+- */
+- public static OpenSslX509KeyManagerFactory newKeyless(InputStream chain)
+- throws CertificateException, IOException,
+- KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
+- return newKeyless(SslContext.toX509Certificates(chain));
- }
-
- /**
-- * Sets the OCSP response.
+- * Returns a new initialized {@link OpenSslX509KeyManagerFactory} which will provide its private key by using the
+- * {@link OpenSslPrivateKeyMethod}.
- */
-- @UnstableApi
-- public void setOcspResponse(byte[] response) {
-- if (!enableOcsp) {
-- throw new IllegalStateException("OCSP stapling is not enabled");
-- }
+- public static OpenSslX509KeyManagerFactory newKeyless(X509Certificate... certificateChain)
+- throws CertificateException, IOException,
+- KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
+- KeyStore store = new OpenSslKeyStore(certificateChain.clone(), true);
+- store.load(null, null);
+- OpenSslX509KeyManagerFactory factory = new OpenSslX509KeyManagerFactory();
+- factory.init(store, null);
+- return factory;
+- }
-
-- if (clientMode) {
-- throw new IllegalStateException("Not a server SSLEngine");
-- }
+- private static final class OpenSslKeyStore extends KeyStore {
+- private OpenSslKeyStore(final X509Certificate[] certificateChain, final boolean keyless) {
+- super(new KeyStoreSpi() {
-
-- synchronized (this) {
-- SSL.setOcspResponse(ssl, response);
+- private final Date creationDate = new Date();
+-
+- @Override
+- public Key engineGetKey(String alias, char[] password) throws UnrecoverableKeyException {
+- if (engineContainsAlias(alias)) {
+- final long privateKeyAddress;
+- if (keyless) {
+- privateKeyAddress = 0;
+- } else {
+- try {
+- privateKeyAddress = SSL.loadPrivateKeyFromEngine(
+- alias, password == null ? null : new String(password));
+- } catch (Exception e) {
+- UnrecoverableKeyException keyException =
+- new UnrecoverableKeyException("Unable to load key from engine");
+- keyException.initCause(e);
+- throw keyException;
+- }
+- }
+- return new OpenSslPrivateKey(privateKeyAddress);
+- }
+- return null;
+- }
+-
+- @Override
+- public Certificate[] engineGetCertificateChain(String alias) {
+- return engineContainsAlias(alias)? certificateChain.clone() : null;
+- }
+-
+- @Override
+- public Certificate engineGetCertificate(String alias) {
+- return engineContainsAlias(alias)? certificateChain[0] : null;
+- }
+-
+- @Override
+- public Date engineGetCreationDate(String alias) {
+- return engineContainsAlias(alias)? creationDate : null;
+- }
+-
+- @Override
+- public void engineSetKeyEntry(String alias, Key key, char[] password, Certificate[] chain)
+- throws KeyStoreException {
+- throw new KeyStoreException("Not supported");
+- }
+-
+- @Override
+- public void engineSetKeyEntry(String alias, byte[] key, Certificate[] chain) throws KeyStoreException {
+- throw new KeyStoreException("Not supported");
+- }
+-
+- @Override
+- public void engineSetCertificateEntry(String alias, Certificate cert) throws KeyStoreException {
+- throw new KeyStoreException("Not supported");
+- }
+-
+- @Override
+- public void engineDeleteEntry(String alias) throws KeyStoreException {
+- throw new KeyStoreException("Not supported");
+- }
+-
+- @Override
+- public Enumeration<String> engineAliases() {
+- return Collections.enumeration(Collections.singleton(SslContext.ALIAS));
+- }
+-
+- @Override
+- public boolean engineContainsAlias(String alias) {
+- return SslContext.ALIAS.equals(alias);
+- }
+-
+- @Override
+- public int engineSize() {
+- return 1;
+- }
+-
+- @Override
+- public boolean engineIsKeyEntry(String alias) {
+- return engineContainsAlias(alias);
+- }
+-
+- @Override
+- public boolean engineIsCertificateEntry(String alias) {
+- return engineContainsAlias(alias);
+- }
+-
+- @Override
+- public String engineGetCertificateAlias(Certificate cert) {
+- if (cert instanceof X509Certificate) {
+- for (X509Certificate x509Certificate : certificateChain) {
+- if (x509Certificate.equals(cert)) {
+- return SslContext.ALIAS;
+- }
+- }
+- }
+- return null;
+- }
+-
+- @Override
+- public void engineStore(OutputStream stream, char[] password) {
+- throw new UnsupportedOperationException();
+- }
+-
+- @Override
+- public void engineLoad(InputStream stream, char[] password) {
+- if (stream != null && password != null) {
+- throw new UnsupportedOperationException();
+- }
+- }
+- }, null, "native");
+-
+- OpenSsl.ensureAvailability();
- }
- }
+-}
+diff --git a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslClientContext.java b/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslClientContext.java
+deleted file mode 100644
+index 6b945506b9..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslClientContext.java
++++ /dev/null
+@@ -1,343 +0,0 @@
+-/*
+- * Copyright 2016 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- * http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-package io.netty.handler.ssl;
+-
+-import io.netty.internal.tcnative.CertificateCallback;
+-import io.netty.util.internal.SuppressJava6Requirement;
+-import io.netty.util.internal.SystemPropertyUtil;
+-import io.netty.util.internal.logging.InternalLogger;
+-import io.netty.util.internal.logging.InternalLoggerFactory;
+-import io.netty.internal.tcnative.SSL;
+-import io.netty.internal.tcnative.SSLContext;
+-
+-import java.security.KeyStore;
+-import java.security.PrivateKey;
+-import java.security.cert.X509Certificate;
+-
+-import java.util.Arrays;
+-import java.util.Collections;
+-import java.util.HashSet;
+-import java.util.LinkedHashSet;
+-import java.util.Set;
-
-- /**
-- * Returns the OCSP response or {@code null} if the server didn't provide a stapled OCSP response.
-- */
-- @UnstableApi
-- public byte[] getOcspResponse() {
-- if (!enableOcsp) {
-- throw new IllegalStateException("OCSP stapling is not enabled");
-- }
+-import javax.net.ssl.KeyManagerFactory;
+-import javax.net.ssl.SSLException;
+-import javax.net.ssl.TrustManagerFactory;
+-import javax.net.ssl.X509ExtendedTrustManager;
+-import javax.net.ssl.X509TrustManager;
+-import javax.security.auth.x500.X500Principal;
-
-- if (!clientMode) {
-- throw new IllegalStateException("Not a client SSLEngine");
-- }
+-/**
+- * A client-side {@link SslContext} which uses OpenSSL's SSL/TLS implementation.
+- * <p>Instances of this class must be {@link #release() released} or else native memory will leak!
+- *
+- * <p>Instances of this class <strong>must not</strong> be released before any {@link ReferenceCountedOpenSslEngine}
+- * which depends upon the instance of this class is released. Otherwise if any method of
+- * {@link ReferenceCountedOpenSslEngine} is called which uses this class's JNI resources the JVM may crash.
+- */
+-public final class ReferenceCountedOpenSslClientContext extends ReferenceCountedOpenSslContext {
+- private static final InternalLogger logger =
+- InternalLoggerFactory.getInstance(ReferenceCountedOpenSslClientContext.class);
+- private static final Set<String> SUPPORTED_KEY_TYPES = Collections.unmodifiableSet(new LinkedHashSet<String>(
+- Arrays.asList(OpenSslKeyMaterialManager.KEY_TYPE_RSA,
+- OpenSslKeyMaterialManager.KEY_TYPE_DH_RSA,
+- OpenSslKeyMaterialManager.KEY_TYPE_EC,
+- OpenSslKeyMaterialManager.KEY_TYPE_EC_RSA,
+- OpenSslKeyMaterialManager.KEY_TYPE_EC_EC)));
+- private static final boolean ENABLE_SESSION_TICKET =
+- SystemPropertyUtil.getBoolean("jdk.tls.client.enableSessionTicketExtension", false);
+- private final OpenSslSessionContext sessionContext;
-
-- synchronized (this) {
-- return SSL.getOcspResponse(ssl);
+- ReferenceCountedOpenSslClientContext(X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory,
+- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword,
+- KeyManagerFactory keyManagerFactory, Iterable<String> ciphers,
+- CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
+- String[] protocols, long sessionCacheSize, long sessionTimeout,
+- boolean enableOcsp, String keyStore) throws SSLException {
+- super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, SSL.SSL_MODE_CLIENT, keyCertChain,
+- ClientAuth.NONE, protocols, false, enableOcsp, true);
+- boolean success = false;
+- try {
+- sessionContext = newSessionContext(this, ctx, engineMap, trustCertCollection, trustManagerFactory,
+- keyCertChain, key, keyPassword, keyManagerFactory, keyStore);
+- if (ENABLE_SESSION_TICKET) {
+- sessionContext.setTicketKeys();
+- }
+- success = true;
+- } finally {
+- if (!success) {
+- release();
+- }
- }
- }
-
- @Override
-- public final int refCnt() {
-- return refCnt.refCnt();
-- }
--
-- @Override
-- public final ReferenceCounted retain() {
-- refCnt.retain();
-- return this;
+- public OpenSslSessionContext sessionContext() {
+- return sessionContext;
- }
-
-- @Override
-- public final ReferenceCounted retain(int increment) {
-- refCnt.retain(increment);
-- return this;
-- }
+- static OpenSslSessionContext newSessionContext(ReferenceCountedOpenSslContext thiz, long ctx,
+- OpenSslEngineMap engineMap,
+- X509Certificate[] trustCertCollection,
+- TrustManagerFactory trustManagerFactory,
+- X509Certificate[] keyCertChain, PrivateKey key,
+- String keyPassword, KeyManagerFactory keyManagerFactory,
+- String keyStore) throws SSLException {
+- if (key == null && keyCertChain != null || key != null && keyCertChain == null) {
+- throw new IllegalArgumentException(
+- "Either both keyCertChain and key needs to be null or none of them");
+- }
+- OpenSslKeyMaterialProvider keyMaterialProvider = null;
+- try {
+- try {
+- if (!OpenSsl.useKeyManagerFactory()) {
+- if (keyManagerFactory != null) {
+- throw new IllegalArgumentException(
+- "KeyManagerFactory not supported");
+- }
+- if (keyCertChain != null/* && key != null*/) {
+- setKeyMaterial(ctx, keyCertChain, key, keyPassword);
+- }
+- } else {
+- // javadocs state that keyManagerFactory has precedent over keyCertChain
+- if (keyManagerFactory == null && keyCertChain != null) {
+- char[] keyPasswordChars = keyStorePassword(keyPassword);
+- KeyStore ks = buildKeyStore(keyCertChain, key, keyPasswordChars, keyStore);
+- if (ks.aliases().hasMoreElements()) {
+- keyManagerFactory = new OpenSslX509KeyManagerFactory();
+- } else {
+- keyManagerFactory = new OpenSslCachingX509KeyManagerFactory(
+- KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()));
+- }
+- keyManagerFactory.init(ks, keyPasswordChars);
+- keyMaterialProvider = providerFor(keyManagerFactory, keyPassword);
+- } else if (keyManagerFactory != null) {
+- keyMaterialProvider = providerFor(keyManagerFactory, keyPassword);
+- }
-
-- @Override
-- public final ReferenceCounted touch() {
-- refCnt.touch();
-- return this;
-- }
+- if (keyMaterialProvider != null) {
+- OpenSslKeyMaterialManager materialManager = new OpenSslKeyMaterialManager(keyMaterialProvider);
+- SSLContext.setCertificateCallback(ctx, new OpenSslClientCertificateCallback(
+- engineMap, materialManager));
+- }
+- }
+- } catch (Exception e) {
+- throw new SSLException("failed to set certificate and key", e);
+- }
-
-- @Override
-- public final ReferenceCounted touch(Object hint) {
-- refCnt.touch(hint);
-- return this;
-- }
+- // On the client side we always need to use SSL_CVERIFY_OPTIONAL (which will translate to SSL_VERIFY_PEER)
+- // to ensure that when the TrustManager throws we will produce the correct alert back to the server.
+- //
+- // See:
+- // - https://www.openssl.org/docs/man1.0.2/man3/SSL_CTX_set_verify.html
+- // - https://github.com/netty/netty/issues/8942
+- SSLContext.setVerify(ctx, SSL.SSL_CVERIFY_OPTIONAL, VERIFY_DEPTH);
-
-- @Override
-- public final boolean release() {
-- return refCnt.release();
-- }
+- try {
+- if (trustCertCollection != null) {
+- trustManagerFactory = buildTrustManagerFactory(trustCertCollection, trustManagerFactory, keyStore);
+- } else if (trustManagerFactory == null) {
+- trustManagerFactory = TrustManagerFactory.getInstance(
+- TrustManagerFactory.getDefaultAlgorithm());
+- trustManagerFactory.init((KeyStore) null);
+- }
+- final X509TrustManager manager = chooseTrustManager(trustManagerFactory.getTrustManagers());
-
-- @Override
-- public final boolean release(int decrement) {
-- return refCnt.release(decrement);
-- }
+- // IMPORTANT: The callbacks set for verification must be static to prevent memory leak as
+- // otherwise the context can never be collected. This is because the JNI code holds
+- // a global reference to the callbacks.
+- //
+- // See https://github.com/netty/netty/issues/5372
-
-- @Override
-- public final synchronized SSLSession getHandshakeSession() {
-- // Javadocs state return value should be:
-- // null if this instance is not currently handshaking, or if the current handshake has not
-- // progressed far enough to create a basic SSLSession. Otherwise, this method returns the
-- // SSLSession currently being negotiated.
-- switch(handshakeState) {
-- case NOT_STARTED:
-- case FINISHED:
-- return null;
-- default:
-- return session;
+- setVerifyCallback(ctx, engineMap, manager);
+- } catch (Exception e) {
+- if (keyMaterialProvider != null) {
+- keyMaterialProvider.destroy();
+- }
+- throw new SSLException("unable to setup trustmanager", e);
+- }
+- OpenSslClientSessionContext context = new OpenSslClientSessionContext(thiz, keyMaterialProvider);
+- keyMaterialProvider = null;
+- return context;
+- } finally {
+- if (keyMaterialProvider != null) {
+- keyMaterialProvider.destroy();
+- }
- }
- }
-
-- /**
-- * Returns the pointer to the {@code SSL} object for this {@link ReferenceCountedOpenSslEngine}.
-- * Be aware that it is freed as soon as the {@link #release()} or {@link #shutdown()} methods are called.
-- * At this point {@code 0} will be returned.
-- */
-- public final synchronized long sslPointer() {
-- return ssl;
+- @SuppressJava6Requirement(reason = "Guarded by java version check")
+- private static void setVerifyCallback(long ctx, OpenSslEngineMap engineMap, X509TrustManager manager) {
+- // Use this to prevent an error when running on java < 7
+- if (useExtendedTrustManager(manager)) {
+- SSLContext.setCertVerifyCallback(ctx,
+- new ExtendedTrustManagerVerifyCallback(engineMap, (X509ExtendedTrustManager) manager));
+- } else {
+- SSLContext.setCertVerifyCallback(ctx, new TrustManagerVerifyCallback(engineMap, manager));
+- }
- }
-
-- /**
-- * Destroys this engine.
-- */
-- public final synchronized void shutdown() {
-- if (DESTROYED_UPDATER.compareAndSet(this, 0, 1)) {
-- engineMap.remove(ssl);
-- SSL.freeSSL(ssl);
-- ssl = networkBIO = 0;
--
-- isInboundDone = outboundClosed = true;
+- // No cache is currently supported for client side mode.
+- static final class OpenSslClientSessionContext extends OpenSslSessionContext {
+- OpenSslClientSessionContext(ReferenceCountedOpenSslContext context, OpenSslKeyMaterialProvider provider) {
+- super(context, provider);
- }
-
-- // On shutdown clear all errors
-- SSL.clearError();
-- }
+- @Override
+- public void setSessionTimeout(int seconds) {
+- if (seconds < 0) {
+- throw new IllegalArgumentException();
+- }
+- }
-
-- /**
-- * Write plaintext data to the OpenSSL internal BIO
-- *
-- * Calling this function with src.remaining == 0 is undefined.
-- */
-- private int writePlaintextData(final ByteBuffer src, int len) {
-- final int pos = src.position();
-- final int limit = src.limit();
-- final int sslWrote;
+- @Override
+- public int getSessionTimeout() {
+- return 0;
+- }
-
-- if (src.isDirect()) {
-- sslWrote = SSL.writeToSSL(ssl, Buffer.address(src) + pos, len);
-- if (sslWrote > 0) {
-- src.position(pos + sslWrote);
+- @Override
+- public void setSessionCacheSize(int size) {
+- if (size < 0) {
+- throw new IllegalArgumentException();
- }
-- } else {
-- ByteBuf buf = alloc.directBuffer(len);
-- try {
-- src.limit(pos + len);
+- }
-
-- buf.setBytes(0, src);
-- src.limit(limit);
+- @Override
+- public int getSessionCacheSize() {
+- return 0;
+- }
-
-- sslWrote = SSL.writeToSSL(ssl, memoryAddress(buf), len);
-- if (sslWrote > 0) {
-- src.position(pos + sslWrote);
-- } else {
-- src.position(pos);
-- }
-- } finally {
-- buf.release();
-- }
+- @Override
+- public void setSessionCacheEnabled(boolean enabled) {
+- // ignored
+- }
+-
+- @Override
+- public boolean isSessionCacheEnabled() {
+- return false;
- }
-- return sslWrote;
- }
-
-- /**
-- * Write encrypted data to the OpenSSL network BIO.
-- */
-- private ByteBuf writeEncryptedData(final ByteBuffer src, int len) {
-- final int pos = src.position();
-- if (src.isDirect()) {
-- SSL.bioSetByteBuffer(networkBIO, Buffer.address(src) + pos, len, false);
-- } else {
-- final ByteBuf buf = alloc.directBuffer(len);
-- try {
-- final int limit = src.limit();
-- src.limit(pos + len);
-- buf.writeBytes(src);
-- // Restore the original position and limit because we don't want to consume from `src`.
-- src.position(pos);
-- src.limit(limit);
+- private static final class TrustManagerVerifyCallback extends AbstractCertificateVerifier {
+- private final X509TrustManager manager;
-
-- SSL.bioSetByteBuffer(networkBIO, memoryAddress(buf), len, false);
-- return buf;
-- } catch (Throwable cause) {
-- buf.release();
-- PlatformDependent.throwException(cause);
-- }
+- TrustManagerVerifyCallback(OpenSslEngineMap engineMap, X509TrustManager manager) {
+- super(engineMap);
+- this.manager = manager;
- }
-- return null;
-- }
-
-- /**
-- * Read plaintext data from the OpenSSL internal BIO
-- */
-- private int readPlaintextData(final ByteBuffer dst) {
-- final int sslRead;
-- final int pos = dst.position();
-- if (dst.isDirect()) {
-- sslRead = SSL.readFromSSL(ssl, Buffer.address(dst) + pos, dst.limit() - pos);
-- if (sslRead > 0) {
-- dst.position(pos + sslRead);
-- }
-- } else {
-- final int limit = dst.limit();
-- final int len = min(MAX_ENCRYPTED_PACKET_LENGTH, limit - pos);
-- final ByteBuf buf = alloc.directBuffer(len);
-- try {
-- sslRead = SSL.readFromSSL(ssl, memoryAddress(buf), len);
-- if (sslRead > 0) {
-- dst.limit(pos + sslRead);
-- buf.getBytes(buf.readerIndex(), dst);
-- dst.limit(limit);
-- }
-- } finally {
-- buf.release();
-- }
+- @Override
+- void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts, String auth)
+- throws Exception {
+- manager.checkServerTrusted(peerCerts, auth);
- }
--
-- return sslRead;
- }
-
-- @Override
-- public final SSLEngineResult wrap(
-- final ByteBuffer[] srcs, int offset, final int length, final ByteBuffer dst) throws SSLException {
-- // Throw required runtime exceptions
-- if (srcs == null) {
-- throw new IllegalArgumentException("srcs is null");
-- }
-- if (dst == null) {
-- throw new IllegalArgumentException("dst is null");
+- @SuppressJava6Requirement(reason = "Usage guarded by java version check")
+- private static final class ExtendedTrustManagerVerifyCallback extends AbstractCertificateVerifier {
+- private final X509ExtendedTrustManager manager;
+-
+- ExtendedTrustManagerVerifyCallback(OpenSslEngineMap engineMap, X509ExtendedTrustManager manager) {
+- super(engineMap);
+- this.manager = OpenSslTlsv13X509ExtendedTrustManager.wrap(manager);
- }
-
-- if (offset >= srcs.length || offset + length > srcs.length) {
-- throw new IndexOutOfBoundsException(
-- "offset: " + offset + ", length: " + length +
-- " (expected: offset <= offset + length <= srcs.length (" + srcs.length + "))");
+- @Override
+- void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts, String auth)
+- throws Exception {
+- manager.checkServerTrusted(peerCerts, auth, engine);
- }
+- }
-
-- if (dst.isReadOnly()) {
-- throw new ReadOnlyBufferException();
+- private static final class OpenSslClientCertificateCallback implements CertificateCallback {
+- private final OpenSslEngineMap engineMap;
+- private final OpenSslKeyMaterialManager keyManagerHolder;
+-
+- OpenSslClientCertificateCallback(OpenSslEngineMap engineMap, OpenSslKeyMaterialManager keyManagerHolder) {
+- this.engineMap = engineMap;
+- this.keyManagerHolder = keyManagerHolder;
- }
-
-- synchronized (this) {
-- if (isOutboundDone()) {
-- // All drained in the outbound buffer
-- return isInboundDone() || isDestroyed() ? CLOSED_NOT_HANDSHAKING : NEED_UNWRAP_CLOSED;
+- @Override
+- public void handle(long ssl, byte[] keyTypeBytes, byte[][] asn1DerEncodedPrincipals) throws Exception {
+- final ReferenceCountedOpenSslEngine engine = engineMap.get(ssl);
+- // May be null if it was destroyed in the meantime.
+- if (engine == null) {
+- return;
- }
--
-- int bytesProduced = 0;
-- ByteBuf bioReadCopyBuf = null;
- try {
-- // Setup the BIO buffer so that we directly write the encryption results into dst.
-- if (dst.isDirect()) {
-- SSL.bioSetByteBuffer(networkBIO, Buffer.address(dst) + dst.position(), dst.remaining(),
-- true);
+- final Set<String> keyTypesSet = supportedClientKeyTypes(keyTypeBytes);
+- final String[] keyTypes = keyTypesSet.toArray(new String[0]);
+- final X500Principal[] issuers;
+- if (asn1DerEncodedPrincipals == null) {
+- issuers = null;
- } else {
-- bioReadCopyBuf = alloc.directBuffer(dst.remaining());
-- SSL.bioSetByteBuffer(networkBIO, memoryAddress(bioReadCopyBuf), bioReadCopyBuf.writableBytes(),
-- true);
-- }
--
-- int bioLengthBefore = SSL.bioLengthByteBuffer(networkBIO);
--
-- // Explicit use outboundClosed as we want to drain any bytes that are still present.
-- if (outboundClosed) {
-- // There is something left to drain.
-- // See https://github.com/netty/netty/issues/6260
-- bytesProduced = SSL.bioFlushByteBuffer(networkBIO);
-- if (bytesProduced <= 0) {
-- return newResultMayFinishHandshake(NOT_HANDSHAKING, 0, 0);
-- }
-- // It is possible when the outbound was closed there was not enough room in the non-application
-- // buffers to hold the close_notify. We should keep trying to close until we consume all the data
-- // OpenSSL can give us.
-- if (!doSSLShutdown()) {
-- return newResultMayFinishHandshake(NOT_HANDSHAKING, 0, bytesProduced);
+- issuers = new X500Principal[asn1DerEncodedPrincipals.length];
+- for (int i = 0; i < asn1DerEncodedPrincipals.length; i++) {
+- issuers[i] = new X500Principal(asn1DerEncodedPrincipals[i]);
- }
-- bytesProduced = bioLengthBefore - SSL.bioLengthByteBuffer(networkBIO);
-- return newResultMayFinishHandshake(NEED_WRAP, 0, bytesProduced);
- }
+- keyManagerHolder.setKeyMaterialClientSide(engine, keyTypes, issuers);
+- } catch (Throwable cause) {
+- logger.debug("request of key failed", cause);
+- engine.initHandshakeException(cause);
+- }
+- }
-
-- // Flush any data that may be implicitly generated by OpenSSL (handshake, close, etc..).
-- SSLEngineResult.HandshakeStatus status = NOT_HANDSHAKING;
-- // Prepare OpenSSL to work in server mode and receive handshake
-- if (handshakeState != HandshakeState.FINISHED) {
-- if (handshakeState != HandshakeState.STARTED_EXPLICITLY) {
-- // Update accepted so we know we triggered the handshake via wrap
-- handshakeState = HandshakeState.STARTED_IMPLICITLY;
-- }
--
-- // Flush any data that may have been written implicitly during the handshake by OpenSSL.
-- bytesProduced = SSL.bioFlushByteBuffer(networkBIO);
--
-- if (bytesProduced > 0 && handshakeException != null) {
-- // TODO(scott): It is possible that when the handshake failed there was not enough room in the
-- // non-application buffers to hold the alert. We should get all the data before progressing on.
-- // However I'm not aware of a way to do this with the OpenSSL APIs.
-- // See https://github.com/netty/netty/issues/6385.
--
-- // We produced / consumed some data during the handshake, signal back to the caller.
-- // If there is a handshake exception and we have produced data, we should send the data before
-- // we allow handshake() to throw the handshake exception.
-- return newResult(NEED_WRAP, 0, bytesProduced);
-- }
--
-- status = handshake();
+- /**
+- * Gets the supported key types for client certificates.
+- *
+- * @param clientCertificateTypes {@code ClientCertificateType} values provided by the server.
+- * See https://www.ietf.org/assignments/tls-parameters/tls-parameters.xml.
+- * @return supported key types that can be used in {@code X509KeyManager.chooseClientAlias} and
+- * {@code X509ExtendedKeyManager.chooseEngineClientAlias}.
+- */
+- private static Set<String> supportedClientKeyTypes(byte[] clientCertificateTypes) {
+- if (clientCertificateTypes == null) {
+- // Try all of the supported key types.
+- return SUPPORTED_KEY_TYPES;
+- }
+- Set<String> result = new HashSet<String>(clientCertificateTypes.length);
+- for (byte keyTypeCode : clientCertificateTypes) {
+- String keyType = clientKeyType(keyTypeCode);
+- if (keyType == null) {
+- // Unsupported client key type -- ignore
+- continue;
+- }
+- result.add(keyType);
+- }
+- return result;
+- }
-
-- if (renegotiationPending && status == FINISHED) {
-- // If renegotiationPending is true that means when we attempted to start renegotiation
-- // the BIO buffer didn't have enough space to hold the HelloRequest which prompts the
-- // client to initiate a renegotiation. At this point the HelloRequest has been written
-- // so we can actually start the handshake process.
-- renegotiationPending = false;
-- SSL.setState(ssl, SSL.SSL_ST_ACCEPT);
-- handshakeState = HandshakeState.STARTED_EXPLICITLY;
-- status = handshake();
-- }
+- private static String clientKeyType(byte clientCertificateType) {
+- // See also http://www.ietf.org/assignments/tls-parameters/tls-parameters.xml
+- switch (clientCertificateType) {
+- case CertificateCallback.TLS_CT_RSA_SIGN:
+- return OpenSslKeyMaterialManager.KEY_TYPE_RSA; // RFC rsa_sign
+- case CertificateCallback.TLS_CT_RSA_FIXED_DH:
+- return OpenSslKeyMaterialManager.KEY_TYPE_DH_RSA; // RFC rsa_fixed_dh
+- case CertificateCallback.TLS_CT_ECDSA_SIGN:
+- return OpenSslKeyMaterialManager.KEY_TYPE_EC; // RFC ecdsa_sign
+- case CertificateCallback.TLS_CT_RSA_FIXED_ECDH:
+- return OpenSslKeyMaterialManager.KEY_TYPE_EC_RSA; // RFC rsa_fixed_ecdh
+- case CertificateCallback.TLS_CT_ECDSA_FIXED_ECDH:
+- return OpenSslKeyMaterialManager.KEY_TYPE_EC_EC; // RFC ecdsa_fixed_ecdh
+- default:
+- return null;
+- }
+- }
+- }
+-}
+diff --git a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslContext.java b/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslContext.java
+deleted file mode 100644
+index 27eb43574c..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslContext.java
++++ /dev/null
+@@ -1,968 +0,0 @@
+-/*
+- * Copyright 2016 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- * http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-package io.netty.handler.ssl;
-
-- // Handshake may have generated more data, for example if the internal SSL buffer is small
-- // we may have freed up space by flushing above.
-- bytesProduced = bioLengthBefore - SSL.bioLengthByteBuffer(networkBIO);
+-import io.netty.buffer.ByteBuf;
+-import io.netty.buffer.ByteBufAllocator;
+-import io.netty.internal.tcnative.CertificateVerifier;
+-import io.netty.internal.tcnative.SSL;
+-import io.netty.internal.tcnative.SSLContext;
+-import io.netty.internal.tcnative.SSLPrivateKeyMethod;
+-import io.netty.util.AbstractReferenceCounted;
+-import io.netty.util.ReferenceCounted;
+-import io.netty.util.ResourceLeakDetector;
+-import io.netty.util.ResourceLeakDetectorFactory;
+-import io.netty.util.ResourceLeakTracker;
+-import io.netty.util.internal.ObjectUtil;
+-import io.netty.util.internal.PlatformDependent;
+-import io.netty.util.internal.StringUtil;
+-import io.netty.util.internal.SuppressJava6Requirement;
+-import io.netty.util.internal.SystemPropertyUtil;
+-import io.netty.util.internal.UnstableApi;
+-import io.netty.util.internal.logging.InternalLogger;
+-import io.netty.util.internal.logging.InternalLoggerFactory;
-
-- if (bytesProduced > 0) {
-- // If we have filled up the dst buffer and we have not finished the handshake we should try to
-- // wrap again. Otherwise we should only try to wrap again if there is still data pending in
-- // SSL buffers.
-- return newResult(mayFinishHandshake(status != FINISHED ?
-- bytesProduced == bioLengthBefore ? NEED_WRAP :
-- getHandshakeStatus(SSL.bioLengthNonApplication(networkBIO)) : FINISHED),
-- 0, bytesProduced);
-- }
+-import java.security.PrivateKey;
+-import java.security.SignatureException;
+-import java.security.cert.CertPathValidatorException;
+-import java.security.cert.Certificate;
+-import java.security.cert.CertificateExpiredException;
+-import java.security.cert.CertificateNotYetValidException;
+-import java.security.cert.CertificateRevokedException;
+-import java.security.cert.X509Certificate;
+-import java.util.Arrays;
+-import java.util.Collections;
+-import java.util.List;
+-import java.util.Map;
+-import java.util.concurrent.Executor;
+-import java.util.concurrent.locks.Lock;
+-import java.util.concurrent.locks.ReadWriteLock;
+-import java.util.concurrent.locks.ReentrantReadWriteLock;
-
-- if (status == NEED_UNWRAP) {
-- // Signal if the outbound is done or not.
-- return isOutboundDone() ? NEED_UNWRAP_CLOSED : NEED_UNWRAP_OK;
-- }
+-import javax.net.ssl.KeyManager;
+-import javax.net.ssl.KeyManagerFactory;
+-import javax.net.ssl.SSLEngine;
+-import javax.net.ssl.SSLException;
+-import javax.net.ssl.SSLHandshakeException;
+-import javax.net.ssl.TrustManager;
+-import javax.net.ssl.X509ExtendedTrustManager;
+-import javax.net.ssl.X509KeyManager;
+-import javax.net.ssl.X509TrustManager;
-
-- // Explicit use outboundClosed and not outboundClosed() as we want to drain any bytes that are
-- // still present.
-- if (outboundClosed) {
-- bytesProduced = SSL.bioFlushByteBuffer(networkBIO);
-- return newResultMayFinishHandshake(status, 0, bytesProduced);
-- }
-- }
+-import static io.netty.handler.ssl.OpenSsl.DEFAULT_CIPHERS;
+-import static io.netty.handler.ssl.OpenSsl.availableJavaCipherSuites;
+-import static io.netty.util.internal.ObjectUtil.checkNotNull;
+-import static io.netty.util.internal.ObjectUtil.checkPositiveOrZero;
-
-- int srcsLen = 0;
-- final int endOffset = offset + length;
-- for (int i = offset; i < endOffset; ++i) {
-- final ByteBuffer src = srcs[i];
-- if (src == null) {
-- throw new IllegalArgumentException("srcs[" + i + "] is null");
-- }
-- if (srcsLen == MAX_PLAINTEXT_LENGTH) {
-- continue;
-- }
+-/**
+- * An implementation of {@link SslContext} which works with libraries that support the
+- * <a href="https://www.openssl.org/">OpenSsl</a> C library API.
+- * <p>Instances of this class must be {@link #release() released} or else native memory will leak!
+- *
+- * <p>Instances of this class <strong>must not</strong> be released before any {@link ReferenceCountedOpenSslEngine}
+- * which depends upon the instance of this class is released. Otherwise if any method of
+- * {@link ReferenceCountedOpenSslEngine} is called which uses this class's JNI resources the JVM may crash.
+- */
+-public abstract class ReferenceCountedOpenSslContext extends SslContext implements ReferenceCounted {
+- private static final InternalLogger logger =
+- InternalLoggerFactory.getInstance(ReferenceCountedOpenSslContext.class);
-
-- srcsLen += src.remaining();
-- if (srcsLen > MAX_PLAINTEXT_LENGTH || srcsLen < 0) {
-- // If srcLen > MAX_PLAINTEXT_LENGTH or secLen < 0 just set it to MAX_PLAINTEXT_LENGTH.
-- // This also help us to guard against overflow.
-- // We not break out here as we still need to check for null entries in srcs[].
-- srcsLen = MAX_PLAINTEXT_LENGTH;
-- }
-- }
+- private static final int DEFAULT_BIO_NON_APPLICATION_BUFFER_SIZE = Math.max(1,
+- SystemPropertyUtil.getInt("io.netty.handler.ssl.openssl.bioNonApplicationBufferSize",
+- 2048));
+- static final boolean USE_TASKS =
+- SystemPropertyUtil.getBoolean("io.netty.handler.ssl.openssl.useTasks", false);
+- private static final Integer DH_KEY_LENGTH;
+- private static final ResourceLeakDetector<ReferenceCountedOpenSslContext> leakDetector =
+- ResourceLeakDetectorFactory.instance().newResourceLeakDetector(ReferenceCountedOpenSslContext.class);
-
-- // we will only produce a single TLS packet, and we don't aggregate src buffers,
-- // so we always fix the number of buffers to 1 when checking if the dst buffer is large enough.
-- if (dst.remaining() < calculateOutNetBufSize(srcsLen, 1)) {
-- return new SSLEngineResult(BUFFER_OVERFLOW, getHandshakeStatus(), 0, 0);
-- }
+- // TODO: Maybe make configurable ?
+- protected static final int VERIFY_DEPTH = 10;
-
-- // There was no pending data in the network BIO -- encrypt any application data
-- int bytesConsumed = 0;
-- // Flush any data that may have been written implicitly by OpenSSL in case a shutdown/alert occurs.
-- bytesProduced = SSL.bioFlushByteBuffer(networkBIO);
-- for (; offset < endOffset; ++offset) {
-- final ByteBuffer src = srcs[offset];
-- final int remaining = src.remaining();
-- if (remaining == 0) {
-- continue;
-- }
+- /**
+- * The OpenSSL SSL_CTX object.
+- *
+- * <strong>{@link #ctxLock} must be hold while using ctx!</strong>
+- */
+- protected long ctx;
+- private final List<String> unmodifiableCiphers;
+- private final long sessionCacheSize;
+- private final long sessionTimeout;
+- private final OpenSslApplicationProtocolNegotiator apn;
+- private final int mode;
-
-- // Write plaintext application data to the SSL engine
-- int bytesWritten = writePlaintextData(src, min(remaining, MAX_PLAINTEXT_LENGTH - bytesConsumed));
+- // Reference Counting
+- private final ResourceLeakTracker<ReferenceCountedOpenSslContext> leak;
+- private final AbstractReferenceCounted refCnt = new AbstractReferenceCounted() {
+- @Override
+- public ReferenceCounted touch(Object hint) {
+- if (leak != null) {
+- leak.record(hint);
+- }
-
-- if (bytesWritten > 0) {
-- bytesConsumed += bytesWritten;
+- return ReferenceCountedOpenSslContext.this;
+- }
-
-- // Determine how much encrypted data was generated:
-- final int pendingNow = SSL.bioLengthByteBuffer(networkBIO);
-- bytesProduced += bioLengthBefore - pendingNow;
-- bioLengthBefore = pendingNow;
+- @Override
+- protected void deallocate() {
+- destroy();
+- if (leak != null) {
+- boolean closed = leak.close(ReferenceCountedOpenSslContext.this);
+- assert closed;
+- }
+- }
+- };
-
-- return newResultMayFinishHandshake(status, bytesConsumed, bytesProduced);
-- } else {
-- int sslError = SSL.getError(ssl, bytesWritten);
-- if (sslError == SSL.SSL_ERROR_ZERO_RETURN) {
-- // This means the connection was shutdown correctly, close inbound and outbound
-- if (!receivedShutdown) {
-- closeAll();
+- final Certificate[] keyCertChain;
+- final ClientAuth clientAuth;
+- final String[] protocols;
+- final boolean enableOcsp;
+- final OpenSslEngineMap engineMap = new DefaultOpenSslEngineMap();
+- final ReadWriteLock ctxLock = new ReentrantReadWriteLock();
-
-- bytesProduced += bioLengthBefore - SSL.bioLengthByteBuffer(networkBIO);
+- private volatile int bioNonApplicationBufferSize = DEFAULT_BIO_NON_APPLICATION_BUFFER_SIZE;
-
-- // If we have filled up the dst buffer and we have not finished the handshake we should
-- // try to wrap again. Otherwise we should only try to wrap again if there is still data
-- // pending in SSL buffers.
-- SSLEngineResult.HandshakeStatus hs = mayFinishHandshake(
-- status != FINISHED ? bytesProduced == dst.remaining() ? NEED_WRAP
-- : getHandshakeStatus(SSL.bioLengthNonApplication(networkBIO))
-- : FINISHED);
-- return newResult(hs, bytesConsumed, bytesProduced);
-- }
+- @SuppressWarnings("deprecation")
+- static final OpenSslApplicationProtocolNegotiator NONE_PROTOCOL_NEGOTIATOR =
+- new OpenSslApplicationProtocolNegotiator() {
+- @Override
+- public ApplicationProtocolConfig.Protocol protocol() {
+- return ApplicationProtocolConfig.Protocol.NONE;
+- }
-
-- return newResult(NOT_HANDSHAKING, bytesConsumed, bytesProduced);
-- } else if (sslError == SSL.SSL_ERROR_WANT_READ) {
-- // If there is no pending data to read from BIO we should go back to event loop and try
-- // to read more data [1]. It is also possible that event loop will detect the socket has
-- // been closed. [1] https://www.openssl.org/docs/manmaster/ssl/SSL_write.html
-- return newResult(NEED_UNWRAP, bytesConsumed, bytesProduced);
-- } else if (sslError == SSL.SSL_ERROR_WANT_WRITE) {
-- // SSL_ERROR_WANT_WRITE typically means that the underlying transport is not writable
-- // and we should set the "want write" flag on the selector and try again when the
-- // underlying transport is writable [1]. However we are not directly writing to the
-- // underlying transport and instead writing to a BIO buffer. The OpenSsl documentation
-- // says we should do the following [1]:
-- //
-- // "When using a buffering BIO, like a BIO pair, data must be written into or retrieved
-- // out of the BIO before being able to continue."
-- //
-- // So we attempt to drain the BIO buffer below, but if there is no data this condition
-- // is undefined and we assume their is a fatal error with the openssl engine and close.
-- // [1] https://www.openssl.org/docs/manmaster/ssl/SSL_write.html
-- return newResult(NEED_WRAP, bytesConsumed, bytesProduced);
-- } else {
-- // Everything else is considered as error
-- throw shutdownWithError("SSL_write");
-- }
-- }
+- @Override
+- public List<String> protocols() {
+- return Collections.emptyList();
- }
-- return newResultMayFinishHandshake(status, bytesConsumed, bytesProduced);
-- } finally {
-- SSL.bioClearByteBuffer(networkBIO);
-- if (bioReadCopyBuf == null) {
-- dst.position(dst.position() + bytesProduced);
-- } else {
-- assert bioReadCopyBuf.readableBytes() <= dst.remaining() : "The destination buffer " + dst +
-- " didn't have enough remaining space to hold the encrypted content in " + bioReadCopyBuf;
-- dst.put(bioReadCopyBuf.internalNioBuffer(bioReadCopyBuf.readerIndex(), bytesProduced));
-- bioReadCopyBuf.release();
+-
+- @Override
+- public ApplicationProtocolConfig.SelectorFailureBehavior selectorFailureBehavior() {
+- return ApplicationProtocolConfig.SelectorFailureBehavior.CHOOSE_MY_LAST_PROTOCOL;
- }
-- }
-- }
-- }
-
-- private SSLEngineResult newResult(SSLEngineResult.HandshakeStatus hs, int bytesConsumed, int bytesProduced) {
-- return newResult(OK, hs, bytesConsumed, bytesProduced);
-- }
+- @Override
+- public ApplicationProtocolConfig.SelectedListenerFailureBehavior selectedListenerFailureBehavior() {
+- return ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT;
+- }
+- };
-
-- private SSLEngineResult newResult(SSLEngineResult.Status status, SSLEngineResult.HandshakeStatus hs,
-- int bytesConsumed, int bytesProduced) {
-- // If isOutboundDone, then the data from the network BIO
-- // was the close_notify message and all was consumed we are not required to wait
-- // for the receipt the peer's close_notify message -- shutdown.
-- if (isOutboundDone()) {
-- if (isInboundDone()) {
-- // If the inbound was done as well, we need to ensure we return NOT_HANDSHAKING to signal we are done.
-- hs = NOT_HANDSHAKING;
+- static {
+- Integer dhLen = null;
-
-- // As the inbound and the outbound is done we can shutdown the engine now.
-- shutdown();
+- try {
+- String dhKeySize = SystemPropertyUtil.get("jdk.tls.ephemeralDHKeySize");
+- if (dhKeySize != null) {
+- try {
+- dhLen = Integer.valueOf(dhKeySize);
+- } catch (NumberFormatException e) {
+- logger.debug("ReferenceCountedOpenSslContext supports -Djdk.tls.ephemeralDHKeySize={int}, but got: "
+- + dhKeySize);
+- }
- }
-- return new SSLEngineResult(CLOSED, hs, bytesConsumed, bytesProduced);
+- } catch (Throwable ignore) {
+- // ignore
- }
-- return new SSLEngineResult(status, hs, bytesConsumed, bytesProduced);
+- DH_KEY_LENGTH = dhLen;
- }
-
-- private SSLEngineResult newResultMayFinishHandshake(SSLEngineResult.HandshakeStatus hs,
-- int bytesConsumed, int bytesProduced) throws SSLException {
-- return newResult(mayFinishHandshake(hs != FINISHED ? getHandshakeStatus() : FINISHED),
-- bytesConsumed, bytesProduced);
+- ReferenceCountedOpenSslContext(Iterable<String> ciphers, CipherSuiteFilter cipherFilter,
+- ApplicationProtocolConfig apnCfg, long sessionCacheSize, long sessionTimeout,
+- int mode, Certificate[] keyCertChain, ClientAuth clientAuth, String[] protocols,
+- boolean startTls, boolean enableOcsp, boolean leakDetection) throws SSLException {
+- this(ciphers, cipherFilter, toNegotiator(apnCfg), sessionCacheSize, sessionTimeout, mode, keyCertChain,
+- clientAuth, protocols, startTls, enableOcsp, leakDetection);
- }
-
-- private SSLEngineResult newResultMayFinishHandshake(SSLEngineResult.Status status,
-- SSLEngineResult.HandshakeStatus hs,
-- int bytesConsumed, int bytesProduced) throws SSLException {
-- return newResult(status, mayFinishHandshake(hs != FINISHED ? getHandshakeStatus() : FINISHED),
-- bytesConsumed, bytesProduced);
-- }
+- ReferenceCountedOpenSslContext(Iterable<String> ciphers, CipherSuiteFilter cipherFilter,
+- OpenSslApplicationProtocolNegotiator apn, long sessionCacheSize,
+- long sessionTimeout, int mode, Certificate[] keyCertChain,
+- ClientAuth clientAuth, String[] protocols, boolean startTls, boolean enableOcsp,
+- boolean leakDetection) throws SSLException {
+- super(startTls);
-
-- /**
-- * Log the error, shutdown the engine and throw an exception.
-- */
-- private SSLException shutdownWithError(String operations) {
-- String err = SSL.getLastError();
-- return shutdownWithError(operations, err);
-- }
+- OpenSsl.ensureAvailability();
-
-- private SSLException shutdownWithError(String operation, String err) {
-- if (logger.isDebugEnabled()) {
-- logger.debug("{} failed: OpenSSL error: {}", operation, err);
+- if (enableOcsp && !OpenSsl.isOcspSupported()) {
+- throw new IllegalStateException("OCSP is not supported.");
- }
-
-- // There was an internal error -- shutdown
-- shutdown();
-- if (handshakeState == HandshakeState.FINISHED) {
-- return new SSLException(err);
+- if (mode != SSL.SSL_MODE_SERVER && mode != SSL.SSL_MODE_CLIENT) {
+- throw new IllegalArgumentException("mode most be either SSL.SSL_MODE_SERVER or SSL.SSL_MODE_CLIENT");
- }
-- return new SSLHandshakeException(err);
-- }
+- leak = leakDetection ? leakDetector.track(this) : null;
+- this.mode = mode;
+- this.clientAuth = isServer() ? checkNotNull(clientAuth, "clientAuth") : ClientAuth.NONE;
+- this.protocols = protocols;
+- this.enableOcsp = enableOcsp;
-
-- public final SSLEngineResult unwrap(
-- final ByteBuffer[] srcs, int srcsOffset, final int srcsLength,
-- final ByteBuffer[] dsts, int dstsOffset, final int dstsLength) throws SSLException {
+- this.keyCertChain = keyCertChain == null ? null : keyCertChain.clone();
-
-- // Throw required runtime exceptions
-- if (srcs == null) {
-- throw new NullPointerException("srcs");
-- }
-- if (srcsOffset >= srcs.length
-- || srcsOffset + srcsLength > srcs.length) {
-- throw new IndexOutOfBoundsException(
-- "offset: " + srcsOffset + ", length: " + srcsLength +
-- " (expected: offset <= offset + length <= srcs.length (" + srcs.length + "))");
-- }
-- if (dsts == null) {
-- throw new IllegalArgumentException("dsts is null");
-- }
-- if (dstsOffset >= dsts.length || dstsOffset + dstsLength > dsts.length) {
-- throw new IndexOutOfBoundsException(
-- "offset: " + dstsOffset + ", length: " + dstsLength +
-- " (expected: offset <= offset + length <= dsts.length (" + dsts.length + "))");
-- }
-- long capacity = 0;
-- final int dstsEndOffset = dstsOffset + dstsLength;
-- for (int i = dstsOffset; i < dstsEndOffset; i ++) {
-- ByteBuffer dst = dsts[i];
-- if (dst == null) {
-- throw new IllegalArgumentException("dsts[" + i + "] is null");
-- }
-- if (dst.isReadOnly()) {
-- throw new ReadOnlyBufferException();
+- unmodifiableCiphers = Arrays.asList(checkNotNull(cipherFilter, "cipherFilter").filterCipherSuites(
+- ciphers, DEFAULT_CIPHERS, availableJavaCipherSuites()));
+-
+- this.apn = checkNotNull(apn, "apn");
+-
+- // Create a new SSL_CTX and configure it.
+- boolean success = false;
+- try {
+- try {
+- int protocolOpts = SSL.SSL_PROTOCOL_SSLV3 | SSL.SSL_PROTOCOL_TLSV1 |
+- SSL.SSL_PROTOCOL_TLSV1_1 | SSL.SSL_PROTOCOL_TLSV1_2;
+- if (OpenSsl.isTlsv13Supported()) {
+- protocolOpts |= SSL.SSL_PROTOCOL_TLSV1_3;
+- }
+- ctx = SSLContext.make(protocolOpts, mode);
+- } catch (Exception e) {
+- throw new SSLException("failed to create an SSL_CTX", e);
- }
-- capacity += dst.remaining();
-- }
-
-- final int srcsEndOffset = srcsOffset + srcsLength;
-- long len = 0;
-- for (int i = srcsOffset; i < srcsEndOffset; i++) {
-- ByteBuffer src = srcs[i];
-- if (src == null) {
-- throw new IllegalArgumentException("srcs[" + i + "] is null");
+- boolean tlsv13Supported = OpenSsl.isTlsv13Supported();
+- StringBuilder cipherBuilder = new StringBuilder();
+- StringBuilder cipherTLSv13Builder = new StringBuilder();
+-
+- /* List the ciphers that are permitted to negotiate. */
+- try {
+- if (unmodifiableCiphers.isEmpty()) {
+- // Set non TLSv1.3 ciphers.
+- SSLContext.setCipherSuite(ctx, StringUtil.EMPTY_STRING, false);
+- if (tlsv13Supported) {
+- // Set TLSv1.3 ciphers.
+- SSLContext.setCipherSuite(ctx, StringUtil.EMPTY_STRING, true);
+- }
+- } else {
+- CipherSuiteConverter.convertToCipherStrings(
+- unmodifiableCiphers, cipherBuilder, cipherTLSv13Builder, OpenSsl.isBoringSSL());
+-
+- // Set non TLSv1.3 ciphers.
+- SSLContext.setCipherSuite(ctx, cipherBuilder.toString(), false);
+- if (tlsv13Supported) {
+- // Set TLSv1.3 ciphers.
+- SSLContext.setCipherSuite(ctx, cipherTLSv13Builder.toString(), true);
+- }
+- }
+- } catch (SSLException e) {
+- throw e;
+- } catch (Exception e) {
+- throw new SSLException("failed to set cipher suite: " + unmodifiableCiphers, e);
- }
-- len += src.remaining();
-- }
-
-- synchronized (this) {
-- if (isInboundDone()) {
-- return isOutboundDone() || isDestroyed() ? CLOSED_NOT_HANDSHAKING : NEED_WRAP_CLOSED;
+- int options = SSLContext.getOptions(ctx) |
+- SSL.SSL_OP_NO_SSLv2 |
+- SSL.SSL_OP_NO_SSLv3 |
+- // Disable TLSv1.3 by default for now. Even if TLSv1.3 is not supported this will
+- // work fine as in this case SSL_OP_NO_TLSv1_3 will be 0.
+- SSL.SSL_OP_NO_TLSv1_3 |
+-
+- SSL.SSL_OP_CIPHER_SERVER_PREFERENCE |
+-
+- // We do not support compression at the moment so we should explicitly disable it.
+- SSL.SSL_OP_NO_COMPRESSION |
+-
+- // Disable ticket support by default to be more inline with SSLEngineImpl of the JDK.
+- // This also let SSLSession.getId() work the same way for the JDK implementation and the
+- // OpenSSLEngine. If tickets are supported SSLSession.getId() will only return an ID on the
+- // server-side if it could make use of tickets.
+- SSL.SSL_OP_NO_TICKET;
+-
+- if (cipherBuilder.length() == 0) {
+- // No ciphers that are compatible with SSLv2 / SSLv3 / TLSv1 / TLSv1.1 / TLSv1.2
+- options |= SSL.SSL_OP_NO_SSLv2 | SSL.SSL_OP_NO_SSLv3 | SSL.SSL_OP_NO_TLSv1
+- | SSL.SSL_OP_NO_TLSv1_1 | SSL.SSL_OP_NO_TLSv1_2;
- }
-
-- SSLEngineResult.HandshakeStatus status = NOT_HANDSHAKING;
-- // Prepare OpenSSL to work in server mode and receive handshake
-- if (handshakeState != HandshakeState.FINISHED) {
-- if (handshakeState != HandshakeState.STARTED_EXPLICITLY) {
-- // Update accepted so we know we triggered the handshake via wrap
-- handshakeState = HandshakeState.STARTED_IMPLICITLY;
-- }
+- SSLContext.setOptions(ctx, options);
+-
+- // We need to enable SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER as the memory address may change between
+- // calling OpenSSLEngine.wrap(...).
+- // See https://github.com/netty/netty-tcnative/issues/100
+- SSLContext.setMode(ctx, SSLContext.getMode(ctx) | SSL.SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
-
-- status = handshake();
-- if (status == NEED_WRAP) {
-- return NEED_WRAP_OK;
-- }
-- // Check if the inbound is considered to be closed if so let us try to wrap again.
-- if (isInboundDone) {
-- return NEED_WRAP_CLOSED;
-- }
+- if (DH_KEY_LENGTH != null) {
+- SSLContext.setTmpDHLength(ctx, DH_KEY_LENGTH);
- }
-
-- if (len < SSL_RECORD_HEADER_LENGTH) {
-- return newResultMayFinishHandshake(BUFFER_UNDERFLOW, status, 0, 0);
+- List<String> nextProtoList = apn.protocols();
+- /* Set next protocols for next protocol negotiation extension, if specified */
+- if (!nextProtoList.isEmpty()) {
+- String[] appProtocols = nextProtoList.toArray(new String[0]);
+- int selectorBehavior = opensslSelectorFailureBehavior(apn.selectorFailureBehavior());
+-
+- switch (apn.protocol()) {
+- case NPN:
+- SSLContext.setNpnProtos(ctx, appProtocols, selectorBehavior);
+- break;
+- case ALPN:
+- SSLContext.setAlpnProtos(ctx, appProtocols, selectorBehavior);
+- break;
+- case NPN_AND_ALPN:
+- SSLContext.setNpnProtos(ctx, appProtocols, selectorBehavior);
+- SSLContext.setAlpnProtos(ctx, appProtocols, selectorBehavior);
+- break;
+- default:
+- throw new Error();
+- }
- }
-
-- int packetLength = SslUtils.getEncryptedPacketLength(srcs, srcsOffset);
+- /* Set session cache size, if specified */
+- if (sessionCacheSize <= 0) {
+- // Get the default session cache size using SSLContext.setSessionCacheSize()
+- sessionCacheSize = SSLContext.setSessionCacheSize(ctx, 20480);
+- }
+- this.sessionCacheSize = sessionCacheSize;
+- SSLContext.setSessionCacheSize(ctx, sessionCacheSize);
-
-- if (packetLength == SslUtils.NOT_ENCRYPTED) {
-- throw new NotSslRecordException("not an SSL/TLS record");
+- /* Set session timeout, if specified */
+- if (sessionTimeout <= 0) {
+- // Get the default session timeout using SSLContext.setSessionCacheTimeout()
+- sessionTimeout = SSLContext.setSessionCacheTimeout(ctx, 300);
- }
+- this.sessionTimeout = sessionTimeout;
+- SSLContext.setSessionCacheTimeout(ctx, sessionTimeout);
-
-- if (packetLength - SSL_RECORD_HEADER_LENGTH > capacity) {
-- // No enough space in the destination buffer so signal the caller
-- // that the buffer needs to be increased.
-- return newResultMayFinishHandshake(BUFFER_OVERFLOW, status, 0, 0);
+- if (enableOcsp) {
+- SSLContext.enableOcsp(ctx, isClient());
- }
-
-- if (len < packetLength) {
-- // We either have no enough data to read the packet length at all or not enough for reading
-- // the whole packet.
-- return newResultMayFinishHandshake(BUFFER_UNDERFLOW, status, 0, 0);
+- SSLContext.setUseTasks(ctx, USE_TASKS);
+- success = true;
+- } finally {
+- if (!success) {
+- release();
- }
+- }
+- }
-
-- // This must always be the case when we reached here as if not we returned BUFFER_UNDERFLOW.
-- assert srcsOffset < srcsEndOffset;
+- private static int opensslSelectorFailureBehavior(ApplicationProtocolConfig.SelectorFailureBehavior behavior) {
+- switch (behavior) {
+- case NO_ADVERTISE:
+- return SSL.SSL_SELECTOR_FAILURE_NO_ADVERTISE;
+- case CHOOSE_MY_LAST_PROTOCOL:
+- return SSL.SSL_SELECTOR_FAILURE_CHOOSE_MY_LAST_PROTOCOL;
+- default:
+- throw new Error();
+- }
+- }
-
-- // This must always be the case if we reached here.
-- assert capacity > 0;
+- @Override
+- public final List<String> cipherSuites() {
+- return unmodifiableCiphers;
+- }
-
-- // Number of produced bytes
-- int bytesProduced = 0;
-- int bytesConsumed = 0;
-- try {
-- for (; srcsOffset < srcsEndOffset; ++srcsOffset) {
-- ByteBuffer src = srcs[srcsOffset];
-- int remaining = src.remaining();
-- if (remaining == 0) {
-- // We must skip empty buffers as BIO_write will return 0 if asked to write something
-- // with length 0.
-- continue;
-- }
-- // Write more encrypted data into the BIO. Ensure we only read one packet at a time as
-- // stated in the SSLEngine javadocs.
-- int pendingEncryptedBytes = min(packetLength, remaining);
-- ByteBuf bioWriteCopyBuf = writeEncryptedData(src, pendingEncryptedBytes);
-- try {
-- readLoop:
-- for (; dstsOffset < dstsEndOffset; ++dstsOffset) {
-- ByteBuffer dst = dsts[dstsOffset];
-- if (!dst.hasRemaining()) {
-- // No space left in the destination buffer, skip it.
-- continue;
-- }
+- @Override
+- public final long sessionCacheSize() {
+- return sessionCacheSize;
+- }
-
-- int bytesRead = readPlaintextData(dst);
-- // We are directly using the ByteBuffer memory for the write, and so we only know what
-- // has been consumed after we let SSL decrypt the data. At this point we should update
-- // the number of bytes consumed, update the ByteBuffer position, and release temp
-- // ByteBuf.
-- int localBytesConsumed = pendingEncryptedBytes - SSL.bioLengthByteBuffer(networkBIO);
-- bytesConsumed += localBytesConsumed;
-- packetLength -= localBytesConsumed;
-- pendingEncryptedBytes -= localBytesConsumed;
-- src.position(src.position() + localBytesConsumed);
+- @Override
+- public final long sessionTimeout() {
+- return sessionTimeout;
+- }
-
-- if (bytesRead > 0) {
-- bytesProduced += bytesRead;
+- @Override
+- public ApplicationProtocolNegotiator applicationProtocolNegotiator() {
+- return apn;
+- }
-
-- if (!dst.hasRemaining()) {
-- // Move to the next dst buffer as this one is full.
-- continue;
-- }
-- if (packetLength == 0) {
-- // We read everything return now.
-- return newResultMayFinishHandshake(isInboundDone() ? CLOSED : OK, status,
-- bytesConsumed, bytesProduced);
-- }
-- // try to write again to the BIO. stop reading from it by break out of the readLoop.
-- break;
-- } else {
-- int sslError = SSL.getError(ssl, bytesRead);
-- if (sslError == SSL.SSL_ERROR_WANT_READ || sslError == SSL.SSL_ERROR_WANT_WRITE) {
-- // break to the outer loop as we want to read more data which means we need to
-- // write more to the BIO.
-- break readLoop;
-- } else if (sslError == SSL.SSL_ERROR_ZERO_RETURN) {
-- // This means the connection was shutdown correctly, close inbound and outbound
-- if (!receivedShutdown) {
-- closeAll();
-- }
-- return newResultMayFinishHandshake(isInboundDone() ? CLOSED : OK, status,
-- bytesConsumed, bytesProduced);
-- } else {
-- return sslReadErrorResult(SSL.getLastErrorNumber(), bytesConsumed,
-- bytesProduced);
-- }
-- }
-- }
+- @Override
+- public final boolean isClient() {
+- return mode == SSL.SSL_MODE_CLIENT;
+- }
-
-- // Either we have no more dst buffers to put the data, or no more data to generate; we are done.
-- if (dstsOffset >= dstsEndOffset || packetLength == 0) {
-- break;
-- }
-- } finally {
-- if (bioWriteCopyBuf != null) {
-- bioWriteCopyBuf.release();
-- }
-- }
-- }
-- } finally {
-- SSL.bioClearByteBuffer(networkBIO);
-- rejectRemoteInitiatedRenegotiation();
-- }
+- @Override
+- public final SSLEngine newEngine(ByteBufAllocator alloc, String peerHost, int peerPort) {
+- return newEngine0(alloc, peerHost, peerPort, true);
+- }
-
-- // Check to see if we received a close_notify message from the peer.
-- if (!receivedShutdown && (SSL.getShutdown(ssl) & SSL.SSL_RECEIVED_SHUTDOWN) == SSL.SSL_RECEIVED_SHUTDOWN) {
-- closeAll();
-- }
+- @Override
+- protected final SslHandler newHandler(ByteBufAllocator alloc, boolean startTls) {
+- return new SslHandler(newEngine0(alloc, null, -1, false), startTls);
+- }
-
-- return newResultMayFinishHandshake(isInboundDone() ? CLOSED : OK, status, bytesConsumed, bytesProduced);
-- }
+- @Override
+- protected final SslHandler newHandler(ByteBufAllocator alloc, String peerHost, int peerPort, boolean startTls) {
+- return new SslHandler(newEngine0(alloc, peerHost, peerPort, false), startTls);
- }
-
-- private SSLEngineResult sslReadErrorResult(int err, int bytesConsumed, int bytesProduced) throws SSLException {
-- String errStr = SSL.getErrorString(err);
+- @Override
+- protected SslHandler newHandler(ByteBufAllocator alloc, boolean startTls, Executor executor) {
+- return new SslHandler(newEngine0(alloc, null, -1, false), startTls, executor);
+- }
-
-- // Check if we have a pending handshakeException and if so see if we need to consume all pending data from the
-- // BIO first or can just shutdown and throw it now.
-- // This is needed so we ensure close_notify etc is correctly send to the remote peer.
-- // See https://github.com/netty/netty/issues/3900
-- if (SSL.bioLengthNonApplication(networkBIO) > 0) {
-- if (handshakeException == null && handshakeState != HandshakeState.FINISHED) {
-- // we seems to have data left that needs to be transfered and so the user needs
-- // call wrap(...). Store the error so we can pick it up later.
-- handshakeException = new SSLHandshakeException(errStr);
-- }
-- return new SSLEngineResult(OK, NEED_WRAP, bytesConsumed, bytesProduced);
-- }
-- throw shutdownWithError("SSL_read", errStr);
+- @Override
+- protected SslHandler newHandler(ByteBufAllocator alloc, String peerHost, int peerPort,
+- boolean startTls, Executor executor) {
+- return new SslHandler(newEngine0(alloc, peerHost, peerPort, false), executor);
- }
-
-- private void closeAll() throws SSLException {
-- receivedShutdown = true;
-- closeOutbound();
-- closeInbound();
+- SSLEngine newEngine0(ByteBufAllocator alloc, String peerHost, int peerPort, boolean jdkCompatibilityMode) {
+- return new ReferenceCountedOpenSslEngine(this, alloc, peerHost, peerPort, jdkCompatibilityMode, true);
- }
-
-- private void rejectRemoteInitiatedRenegotiation() throws SSLHandshakeException {
-- if (rejectRemoteInitiatedRenegotiation && SSL.getHandshakeCount(ssl) > 1) {
-- // TODO: In future versions me may also want to send a fatal_alert to the client and so notify it
-- // that the renegotiation failed.
-- shutdown();
-- throw new SSLHandshakeException("remote-initiated renegotiation not allowed");
-- }
+- /**
+- * Returns a new server-side {@link SSLEngine} with the current configuration.
+- */
+- @Override
+- public final SSLEngine newEngine(ByteBufAllocator alloc) {
+- return newEngine(alloc, null, -1);
- }
-
-- public final SSLEngineResult unwrap(final ByteBuffer[] srcs, final ByteBuffer[] dsts) throws SSLException {
-- return unwrap(srcs, 0, srcs.length, dsts, 0, dsts.length);
+- /**
+- * Returns the pointer to the {@code SSL_CTX} object for this {@link ReferenceCountedOpenSslContext}.
+- * Be aware that it is freed as soon as the {@link #finalize()} method is called.
+- * At this point {@code 0} will be returned.
+- *
+- * @deprecated this method is considered unsafe as the returned pointer may be released later. Dont use it!
+- */
+- @Deprecated
+- public final long context() {
+- return sslCtxPointer();
- }
-
-- private ByteBuffer[] singleSrcBuffer(ByteBuffer src) {
-- singleSrcBuffer[0] = src;
-- return singleSrcBuffer;
+- /**
+- * Returns the stats of this context.
+- *
+- * @deprecated use {@link #sessionContext#stats()}
+- */
+- @Deprecated
+- public final OpenSslSessionStats stats() {
+- return sessionContext().stats();
- }
-
-- private void resetSingleSrcBuffer() {
-- singleSrcBuffer[0] = null;
+- /**
+- * {@deprecated Renegotiation is not supported}
+- * Specify if remote initiated renegotiation is supported or not. If not supported and the remote side tries
+- * to initiate a renegotiation a {@link SSLHandshakeException} will be thrown during decoding.
+- */
+- @Deprecated
+- public void setRejectRemoteInitiatedRenegotiation(boolean rejectRemoteInitiatedRenegotiation) {
+- if (!rejectRemoteInitiatedRenegotiation) {
+- throw new UnsupportedOperationException("Renegotiation is not supported");
+- }
- }
-
-- private ByteBuffer[] singleDstBuffer(ByteBuffer src) {
-- singleDstBuffer[0] = src;
-- return singleDstBuffer;
+- /**
+- * {@deprecated Renegotiation is not supported}
+- * @return {@code true} because renegotiation is not supported.
+- */
+- @Deprecated
+- public boolean getRejectRemoteInitiatedRenegotiation() {
+- return true;
- }
-
-- private void resetSingleDstBuffer() {
-- singleDstBuffer[0] = null;
+- /**
+- * Set the size of the buffer used by the BIO for non-application based writes
+- * (e.g. handshake, renegotiation, etc...).
+- */
+- public void setBioNonApplicationBufferSize(int bioNonApplicationBufferSize) {
+- this.bioNonApplicationBufferSize =
+- checkPositiveOrZero(bioNonApplicationBufferSize, "bioNonApplicationBufferSize");
+- }
+-
+- /**
+- * Returns the size of the buffer used by the BIO for non-application based writes
+- */
+- public int getBioNonApplicationBufferSize() {
+- return bioNonApplicationBufferSize;
+- }
+-
+- /**
+- * Sets the SSL session ticket keys of this context.
+- *
+- * @deprecated use {@link OpenSslSessionContext#setTicketKeys(byte[])}
+- */
+- @Deprecated
+- public final void setTicketKeys(byte[] keys) {
+- sessionContext().setTicketKeys(keys);
- }
-
- @Override
-- public final synchronized SSLEngineResult unwrap(
-- final ByteBuffer src, final ByteBuffer[] dsts, final int offset, final int length) throws SSLException {
+- public abstract OpenSslSessionContext sessionContext();
+-
+- /**
+- * Returns the pointer to the {@code SSL_CTX} object for this {@link ReferenceCountedOpenSslContext}.
+- * Be aware that it is freed as soon as the {@link #release()} method is called.
+- * At this point {@code 0} will be returned.
+- *
+- * @deprecated this method is considered unsafe as the returned pointer may be released later. Dont use it!
+- */
+- @Deprecated
+- public final long sslCtxPointer() {
+- Lock readerLock = ctxLock.readLock();
+- readerLock.lock();
- try {
-- return unwrap(singleSrcBuffer(src), 0, 1, dsts, offset, length);
+- return SSLContext.getSslCtx(ctx);
- } finally {
-- resetSingleSrcBuffer();
+- readerLock.unlock();
- }
- }
-
-- @Override
-- public final synchronized SSLEngineResult wrap(ByteBuffer src, ByteBuffer dst) throws SSLException {
+- /**
+- * Set the {@link OpenSslPrivateKeyMethod} to use. This allows to offload private-key operations
+- * if needed.
+- *
+- * This method is currently only supported when {@code BoringSSL} is used.
+- *
+- * @param method method to use.
+- */
+- @UnstableApi
+- public final void setPrivateKeyMethod(OpenSslPrivateKeyMethod method) {
+- ObjectUtil.checkNotNull(method, "method");
+- Lock writerLock = ctxLock.writeLock();
+- writerLock.lock();
- try {
-- return wrap(singleSrcBuffer(src), dst);
+- SSLContext.setPrivateKeyMethod(ctx, new PrivateKeyMethod(engineMap, method));
- } finally {
-- resetSingleSrcBuffer();
+- writerLock.unlock();
- }
- }
-
-- @Override
-- public final synchronized SSLEngineResult unwrap(ByteBuffer src, ByteBuffer dst) throws SSLException {
+- public final void setUseTasks(boolean useTasks) {
+- Lock writerLock = ctxLock.writeLock();
+- writerLock.lock();
- try {
-- return unwrap(singleSrcBuffer(src), singleDstBuffer(dst));
+- SSLContext.setUseTasks(ctx, useTasks);
- } finally {
-- resetSingleSrcBuffer();
-- resetSingleDstBuffer();
+- writerLock.unlock();
- }
- }
-
-- @Override
-- public final synchronized SSLEngineResult unwrap(ByteBuffer src, ByteBuffer[] dsts) throws SSLException {
+- // IMPORTANT: This method must only be called from either the constructor or the finalizer as a user MUST never
+- // get access to an OpenSslSessionContext after this method was called to prevent the user from
+- // producing a segfault.
+- private void destroy() {
+- Lock writerLock = ctxLock.writeLock();
+- writerLock.lock();
- try {
-- return unwrap(singleSrcBuffer(src), dsts);
-- } finally {
-- resetSingleSrcBuffer();
-- }
-- }
--
-- @Override
-- public final Runnable getDelegatedTask() {
-- // Currently, we do not delegate SSL computation tasks
-- // TODO: in the future, possibly create tasks to do encrypt / decrypt async
--
-- return null;
-- }
--
-- @Override
-- public final synchronized void closeInbound() throws SSLException {
-- if (isInboundDone) {
-- return;
-- }
--
-- isInboundDone = true;
+- if (ctx != 0) {
+- if (enableOcsp) {
+- SSLContext.disableOcsp(ctx);
+- }
-
-- if (isOutboundDone()) {
-- // Only call shutdown if there is no outbound data pending.
-- // See https://github.com/netty/netty/issues/6167
-- shutdown();
-- }
+- SSLContext.free(ctx);
+- ctx = 0;
-
-- if (handshakeState != HandshakeState.NOT_STARTED && !receivedShutdown) {
-- throw new SSLException(
-- "Inbound closed before receiving peer's close_notify: possible truncation attack?");
+- OpenSslSessionContext context = sessionContext();
+- if (context != null) {
+- context.destroy();
+- }
+- }
+- } finally {
+- writerLock.unlock();
- }
- }
-
-- @Override
-- public final synchronized boolean isInboundDone() {
-- return isInboundDone;
+- protected static X509Certificate[] certificates(byte[][] chain) {
+- X509Certificate[] peerCerts = new X509Certificate[chain.length];
+- for (int i = 0; i < peerCerts.length; i++) {
+- peerCerts[i] = new OpenSslX509Certificate(chain[i]);
+- }
+- return peerCerts;
- }
-
-- @Override
-- public final synchronized void closeOutbound() {
-- if (outboundClosed) {
-- return;
+- protected static X509TrustManager chooseTrustManager(TrustManager[] managers) {
+- for (TrustManager m : managers) {
+- if (m instanceof X509TrustManager) {
+- if (PlatformDependent.javaVersion() >= 7) {
+- return OpenSslX509TrustManagerWrapper.wrapIfNeeded((X509TrustManager) m);
+- }
+- return (X509TrustManager) m;
+- }
- }
+- throw new IllegalStateException("no X509TrustManager found");
+- }
-
-- outboundClosed = true;
--
-- if (handshakeState != HandshakeState.NOT_STARTED && !isDestroyed()) {
-- int mode = SSL.getShutdown(ssl);
-- if ((mode & SSL.SSL_SENT_SHUTDOWN) != SSL.SSL_SENT_SHUTDOWN) {
-- doSSLShutdown();
+- protected static X509KeyManager chooseX509KeyManager(KeyManager[] kms) {
+- for (KeyManager km : kms) {
+- if (km instanceof X509KeyManager) {
+- return (X509KeyManager) km;
- }
-- } else {
-- // engine closing before initial handshake
-- shutdown();
- }
+- throw new IllegalStateException("no X509KeyManager found");
- }
-
- /**
-- * Attempt to call {@link SSL#shutdownSSL(long)}.
-- * @return {@code false} if the call to {@link SSL#shutdownSSL(long)} was not attempted or returned an error.
+- * Translate a {@link ApplicationProtocolConfig} object to a
+- * {@link OpenSslApplicationProtocolNegotiator} object.
+- *
+- * @param config The configuration which defines the translation
+- * @return The results of the translation
- */
-- private boolean doSSLShutdown() {
-- if (SSL.isInInit(ssl) != 0) {
-- // Only try to call SSL_shutdown if we are not in the init state anymore.
-- // Otherwise we will see 'error:140E0197:SSL routines:SSL_shutdown:shutdown while in init' in our logs.
-- //
-- // See also http://hg.nginx.org/nginx/rev/062c189fee20
-- return false;
+- @SuppressWarnings("deprecation")
+- static OpenSslApplicationProtocolNegotiator toNegotiator(ApplicationProtocolConfig config) {
+- if (config == null) {
+- return NONE_PROTOCOL_NEGOTIATOR;
- }
-- int err = SSL.shutdownSSL(ssl);
-- if (err < 0) {
-- int sslErr = SSL.getError(ssl, err);
-- if (sslErr == SSL.SSL_ERROR_SYSCALL || sslErr == SSL.SSL_ERROR_SSL) {
-- if (logger.isDebugEnabled()) {
-- logger.debug("SSL_shutdown failed: OpenSSL error: {}", SSL.getLastError());
+-
+- switch (config.protocol()) {
+- case NONE:
+- return NONE_PROTOCOL_NEGOTIATOR;
+- case ALPN:
+- case NPN:
+- case NPN_AND_ALPN:
+- switch (config.selectedListenerFailureBehavior()) {
+- case CHOOSE_MY_LAST_PROTOCOL:
+- case ACCEPT:
+- switch (config.selectorFailureBehavior()) {
+- case CHOOSE_MY_LAST_PROTOCOL:
+- case NO_ADVERTISE:
+- return new OpenSslDefaultApplicationProtocolNegotiator(
+- config);
+- default:
+- throw new UnsupportedOperationException(
+- new StringBuilder("OpenSSL provider does not support ")
+- .append(config.selectorFailureBehavior())
+- .append(" behavior").toString());
+- }
+- default:
+- throw new UnsupportedOperationException(
+- new StringBuilder("OpenSSL provider does not support ")
+- .append(config.selectedListenerFailureBehavior())
+- .append(" behavior").toString());
- }
-- // There was an internal error -- shutdown
-- shutdown();
-- return false;
-- }
-- SSL.clearError();
+- default:
+- throw new Error();
- }
-- return true;
- }
-
-- @Override
-- public final synchronized boolean isOutboundDone() {
-- // Check if there is anything left in the outbound buffer.
-- // We need to ensure we only call SSL.pendingWrittenBytesInBIO(...) if the engine was not destroyed yet.
-- return outboundClosed && (networkBIO == 0 || SSL.bioLengthNonApplication(networkBIO) == 0);
+- @SuppressJava6Requirement(reason = "Guarded by java version check")
+- static boolean useExtendedTrustManager(X509TrustManager trustManager) {
+- return PlatformDependent.javaVersion() >= 7 && trustManager instanceof X509ExtendedTrustManager;
- }
-
- @Override
-- public final String[] getSupportedCipherSuites() {
-- return OpenSsl.AVAILABLE_CIPHER_SUITES.toArray(new String[OpenSsl.AVAILABLE_CIPHER_SUITES.size()]);
+- public final int refCnt() {
+- return refCnt.refCnt();
- }
-
- @Override
-- public final String[] getEnabledCipherSuites() {
-- final String[] enabled;
-- synchronized (this) {
-- if (!isDestroyed()) {
-- enabled = SSL.getCiphers(ssl);
-- } else {
-- return EmptyArrays.EMPTY_STRINGS;
-- }
-- }
-- if (enabled == null) {
-- return EmptyArrays.EMPTY_STRINGS;
-- } else {
-- synchronized (this) {
-- for (int i = 0; i < enabled.length; i++) {
-- String mapped = toJavaCipherSuite(enabled[i]);
-- if (mapped != null) {
-- enabled[i] = mapped;
-- }
-- }
-- }
-- return enabled;
-- }
+- public final ReferenceCounted retain() {
+- refCnt.retain();
+- return this;
- }
-
- @Override
-- public final void setEnabledCipherSuites(String[] cipherSuites) {
-- checkNotNull(cipherSuites, "cipherSuites");
--
-- final StringBuilder buf = new StringBuilder();
-- for (String c: cipherSuites) {
-- if (c == null) {
-- break;
-- }
--
-- String converted = CipherSuiteConverter.toOpenSsl(c);
-- if (converted == null) {
-- converted = c;
-- }
--
-- if (!OpenSsl.isCipherSuiteAvailable(converted)) {
-- throw new IllegalArgumentException("unsupported cipher suite: " + c + '(' + converted + ')');
-- }
--
-- buf.append(converted);
-- buf.append(':');
-- }
--
-- if (buf.length() == 0) {
-- throw new IllegalArgumentException("empty cipher suites");
-- }
-- buf.setLength(buf.length() - 1);
--
-- final String cipherSuiteSpec = buf.toString();
--
-- synchronized (this) {
-- if (!isDestroyed()) {
-- try {
-- SSL.setCipherSuites(ssl, cipherSuiteSpec);
-- } catch (Exception e) {
-- throw new IllegalStateException("failed to enable cipher suites: " + cipherSuiteSpec, e);
-- }
-- } else {
-- throw new IllegalStateException("failed to enable cipher suites: " + cipherSuiteSpec);
-- }
-- }
+- public final ReferenceCounted retain(int increment) {
+- refCnt.retain(increment);
+- return this;
- }
-
- @Override
-- public final String[] getSupportedProtocols() {
-- return OpenSsl.SUPPORTED_PROTOCOLS_SET.toArray(new String[OpenSsl.SUPPORTED_PROTOCOLS_SET.size()]);
+- public final ReferenceCounted touch() {
+- refCnt.touch();
+- return this;
- }
-
- @Override
-- public final String[] getEnabledProtocols() {
-- List<String> enabled = new ArrayList<String>(6);
-- // Seems like there is no way to explicit disable SSLv2Hello in openssl so it is always enabled
-- enabled.add(OpenSsl.PROTOCOL_SSL_V2_HELLO);
--
-- int opts;
-- synchronized (this) {
-- if (!isDestroyed()) {
-- opts = SSL.getOptions(ssl);
-- } else {
-- return enabled.toArray(new String[1]);
-- }
-- }
-- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_TLSv1, OpenSsl.PROTOCOL_TLS_V1)) {
-- enabled.add(OpenSsl.PROTOCOL_TLS_V1);
-- }
-- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_TLSv1_1, OpenSsl.PROTOCOL_TLS_V1_1)) {
-- enabled.add(OpenSsl.PROTOCOL_TLS_V1_1);
-- }
-- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_TLSv1_2, OpenSsl.PROTOCOL_TLS_V1_2)) {
-- enabled.add(OpenSsl.PROTOCOL_TLS_V1_2);
-- }
-- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_SSLv2, OpenSsl.PROTOCOL_SSL_V2)) {
-- enabled.add(OpenSsl.PROTOCOL_SSL_V2);
-- }
-- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_SSLv3, OpenSsl.PROTOCOL_SSL_V3)) {
-- enabled.add(OpenSsl.PROTOCOL_SSL_V3);
-- }
-- return enabled.toArray(new String[enabled.size()]);
+- public final ReferenceCounted touch(Object hint) {
+- refCnt.touch(hint);
+- return this;
- }
-
-- private static boolean isProtocolEnabled(int opts, int disableMask, String protocolString) {
-- // We also need to check if the actual protocolString is supported as depending on the openssl API
-- // implementations it may use a disableMask of 0 (BoringSSL is doing this for example).
-- return (opts & disableMask) == 0 && OpenSsl.SUPPORTED_PROTOCOLS_SET.contains(protocolString);
+- @Override
+- public final boolean release() {
+- return refCnt.release();
- }
-
- @Override
-- public final void setEnabledProtocols(String[] protocols) {
-- if (protocols == null) {
-- // This is correct from the API docs
-- throw new IllegalArgumentException();
+- public final boolean release(int decrement) {
+- return refCnt.release(decrement);
+- }
+-
+- abstract static class AbstractCertificateVerifier extends CertificateVerifier {
+- private final OpenSslEngineMap engineMap;
+-
+- AbstractCertificateVerifier(OpenSslEngineMap engineMap) {
+- this.engineMap = engineMap;
- }
-- boolean sslv2 = false;
-- boolean sslv3 = false;
-- boolean tlsv1 = false;
-- boolean tlsv1_1 = false;
-- boolean tlsv1_2 = false;
-- for (String p: protocols) {
-- if (!OpenSsl.SUPPORTED_PROTOCOLS_SET.contains(p)) {
-- throw new IllegalArgumentException("Protocol " + p + " is not supported.");
-- }
-- if (p.equals(OpenSsl.PROTOCOL_SSL_V2)) {
-- sslv2 = true;
-- } else if (p.equals(OpenSsl.PROTOCOL_SSL_V3)) {
-- sslv3 = true;
-- } else if (p.equals(OpenSsl.PROTOCOL_TLS_V1)) {
-- tlsv1 = true;
-- } else if (p.equals(OpenSsl.PROTOCOL_TLS_V1_1)) {
-- tlsv1_1 = true;
-- } else if (p.equals(OpenSsl.PROTOCOL_TLS_V1_2)) {
-- tlsv1_2 = true;
+-
+- @Override
+- public final int verify(long ssl, byte[][] chain, String auth) {
+- final ReferenceCountedOpenSslEngine engine = engineMap.get(ssl);
+- if (engine == null) {
+- // May be null if it was destroyed in the meantime.
+- return CertificateVerifier.X509_V_ERR_UNSPECIFIED;
- }
-- }
-- synchronized (this) {
-- if (!isDestroyed()) {
-- // Clear out options which disable protocols
-- SSL.clearOptions(ssl, SSL.SSL_OP_NO_SSLv2 | SSL.SSL_OP_NO_SSLv3 | SSL.SSL_OP_NO_TLSv1 |
-- SSL.SSL_OP_NO_TLSv1_1 | SSL.SSL_OP_NO_TLSv1_2);
+- X509Certificate[] peerCerts = certificates(chain);
+- try {
+- verify(engine, peerCerts, auth);
+- return CertificateVerifier.X509_V_OK;
+- } catch (Throwable cause) {
+- logger.debug("verification of certificate failed", cause);
+- engine.initHandshakeException(cause);
-
-- int opts = 0;
-- if (!sslv2) {
-- opts |= SSL.SSL_OP_NO_SSLv2;
-- }
-- if (!sslv3) {
-- opts |= SSL.SSL_OP_NO_SSLv3;
+- // Try to extract the correct error code that should be used.
+- if (cause instanceof OpenSslCertificateException) {
+- // This will never return a negative error code as its validated when constructing the
+- // OpenSslCertificateException.
+- return ((OpenSslCertificateException) cause).errorCode();
- }
-- if (!tlsv1) {
-- opts |= SSL.SSL_OP_NO_TLSv1;
+- if (cause instanceof CertificateExpiredException) {
+- return CertificateVerifier.X509_V_ERR_CERT_HAS_EXPIRED;
- }
-- if (!tlsv1_1) {
-- opts |= SSL.SSL_OP_NO_TLSv1_1;
+- if (cause instanceof CertificateNotYetValidException) {
+- return CertificateVerifier.X509_V_ERR_CERT_NOT_YET_VALID;
- }
-- if (!tlsv1_2) {
-- opts |= SSL.SSL_OP_NO_TLSv1_2;
+- if (PlatformDependent.javaVersion() >= 7) {
+- return translateToError(cause);
- }
-
-- // Disable protocols we do not want
-- SSL.setOptions(ssl, opts);
-- } else {
-- throw new IllegalStateException("failed to enable protocols: " + Arrays.asList(protocols));
+- // Could not detect a specific error code to use, so fallback to a default code.
+- return CertificateVerifier.X509_V_ERR_UNSPECIFIED;
- }
- }
-- }
--
-- @Override
-- public final SSLSession getSession() {
-- return session;
-- }
--
-- @Override
-- public final synchronized void beginHandshake() throws SSLException {
-- switch (handshakeState) {
-- case STARTED_IMPLICITLY:
-- checkEngineClosed(BEGIN_HANDSHAKE_ENGINE_CLOSED);
-
-- // A user did not start handshake by calling this method by him/herself,
-- // but handshake has been started already by wrap() or unwrap() implicitly.
-- // Because it's the user's first time to call this method, it is unfair to
-- // raise an exception. From the user's standpoint, he or she never asked
-- // for renegotiation.
+- @SuppressJava6Requirement(reason = "Usage guarded by java version check")
+- private static int translateToError(Throwable cause) {
+- if (cause instanceof CertificateRevokedException) {
+- return CertificateVerifier.X509_V_ERR_CERT_REVOKED;
+- }
-
-- handshakeState = HandshakeState.STARTED_EXPLICITLY; // Next time this method is invoked by the user,
-- // we should raise an exception.
-- break;
-- case STARTED_EXPLICITLY:
-- // Nothing to do as the handshake is not done yet.
-- break;
-- case FINISHED:
-- if (clientMode) {
-- // Only supported for server mode at the moment.
-- throw RENEGOTIATION_UNSUPPORTED;
-- }
-- // For renegotiate on the server side we need to issue the following command sequence with openssl:
-- //
-- // SSL_renegotiate(ssl)
-- // SSL_do_handshake(ssl)
-- // ssl->state = SSL_ST_ACCEPT
-- // SSL_do_handshake(ssl)
-- //
-- // Because of this we fall-through to call handshake() after setting the state, as this will also take
-- // care of updating the internal OpenSslSession object.
-- //
-- // See also:
-- // https://github.com/apache/httpd/blob/2.4.16/modules/ssl/ssl_engine_kernel...
-- // http://h71000.www7.hp.com/doc/83final/ba554_90007/ch04s03.html
-- int status;
-- if ((status = SSL.renegotiate(ssl)) != 1 || (status = SSL.doHandshake(ssl)) != 1) {
-- int err = SSL.getError(ssl, status);
-- if (err == SSL.SSL_ERROR_WANT_READ || err == SSL.SSL_ERROR_WANT_WRITE) {
-- // If the internal SSL buffer is small it is possible that doHandshake may "fail" because
-- // there is not enough room to write, so we should wait until the renegotiation has been.
-- renegotiationPending = true;
-- handshakeState = HandshakeState.STARTED_EXPLICITLY;
-- lastAccessed = System.currentTimeMillis();
-- return;
-- } else {
-- throw shutdownWithError("renegotiation failed");
+- // The X509TrustManagerImpl uses a Validator which wraps a CertPathValidatorException into
+- // an CertificateException. So we need to handle the wrapped CertPathValidatorException to be
+- // able to send the correct alert.
+- Throwable wrapped = cause.getCause();
+- while (wrapped != null) {
+- if (wrapped instanceof CertPathValidatorException) {
+- CertPathValidatorException ex = (CertPathValidatorException) wrapped;
+- CertPathValidatorException.Reason reason = ex.getReason();
+- if (reason == CertPathValidatorException.BasicReason.EXPIRED) {
+- return CertificateVerifier.X509_V_ERR_CERT_HAS_EXPIRED;
+- }
+- if (reason == CertPathValidatorException.BasicReason.NOT_YET_VALID) {
+- return CertificateVerifier.X509_V_ERR_CERT_NOT_YET_VALID;
+- }
+- if (reason == CertPathValidatorException.BasicReason.REVOKED) {
+- return CertificateVerifier.X509_V_ERR_CERT_REVOKED;
- }
- }
+- wrapped = wrapped.getCause();
+- }
+- return CertificateVerifier.X509_V_ERR_UNSPECIFIED;
+- }
-
-- SSL.setState(ssl, SSL.SSL_ST_ACCEPT);
+- abstract void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts,
+- String auth) throws Exception;
+- }
-
-- lastAccessed = System.currentTimeMillis();
+- private static final class DefaultOpenSslEngineMap implements OpenSslEngineMap {
+- private final Map<Long, ReferenceCountedOpenSslEngine> engines = PlatformDependent.newConcurrentHashMap();
-
-- // fall-through
-- case NOT_STARTED:
-- handshakeState = HandshakeState.STARTED_EXPLICITLY;
-- handshake();
-- break;
-- default:
-- throw new Error();
+- @Override
+- public ReferenceCountedOpenSslEngine remove(long ssl) {
+- return engines.remove(ssl);
- }
-- }
-
-- private void checkEngineClosed(SSLException cause) throws SSLException {
-- if (isDestroyed()) {
-- throw cause;
+- @Override
+- public void add(ReferenceCountedOpenSslEngine engine) {
+- engines.put(engine.sslPointer(), engine);
- }
-- }
-
-- private static SSLEngineResult.HandshakeStatus pendingStatus(int pendingStatus) {
-- // Depending on if there is something left in the BIO we need to WRAP or UNWRAP
-- return pendingStatus > 0 ? NEED_WRAP : NEED_UNWRAP;
+- @Override
+- public ReferenceCountedOpenSslEngine get(long ssl) {
+- return engines.get(ssl);
+- }
- }
-
-- private static boolean isEmpty(Object[] arr) {
-- return arr == null || arr.length == 0;
-- }
+- static void setKeyMaterial(long ctx, X509Certificate[] keyCertChain, PrivateKey key, String keyPassword)
+- throws SSLException {
+- /* Load the certificate file and private key. */
+- long keyBio = 0;
+- long keyCertChainBio = 0;
+- long keyCertChainBio2 = 0;
+- PemEncoded encoded = null;
+- try {
+- // Only encode one time
+- encoded = PemX509Certificate.toPEM(ByteBufAllocator.DEFAULT, true, keyCertChain);
+- keyCertChainBio = toBIO(ByteBufAllocator.DEFAULT, encoded.retain());
+- keyCertChainBio2 = toBIO(ByteBufAllocator.DEFAULT, encoded.retain());
-
-- private static boolean isEmpty(byte[] cert) {
-- return cert == null || cert.length == 0;
-- }
+- if (key != null) {
+- keyBio = toBIO(ByteBufAllocator.DEFAULT, key);
+- }
-
-- private SSLEngineResult.HandshakeStatus handshake() throws SSLException {
-- if (handshakeState == HandshakeState.FINISHED) {
-- return FINISHED;
+- SSLContext.setCertificateBio(
+- ctx, keyCertChainBio, keyBio,
+- keyPassword == null ? StringUtil.EMPTY_STRING : keyPassword);
+- // We may have more then one cert in the chain so add all of them now.
+- SSLContext.setCertificateChainBio(ctx, keyCertChainBio2, true);
+- } catch (SSLException e) {
+- throw e;
+- } catch (Exception e) {
+- throw new SSLException("failed to set certificate and key", e);
+- } finally {
+- freeBio(keyBio);
+- freeBio(keyCertChainBio);
+- freeBio(keyCertChainBio2);
+- if (encoded != null) {
+- encoded.release();
+- }
- }
-- checkEngineClosed(HANDSHAKE_ENGINE_CLOSED);
+- }
-
-- // Check if we have a pending handshakeException and if so see if we need to consume all pending data from the
-- // BIO first or can just shutdown and throw it now.
-- // This is needed so we ensure close_notify etc is correctly send to the remote peer.
-- // See https://github.com/netty/netty/issues/3900
-- SSLHandshakeException exception = handshakeException;
-- if (exception != null) {
-- if (SSL.bioLengthNonApplication(networkBIO) > 0) {
-- // There is something pending, we need to consume it first via a WRAP so we don't loose anything.
-- return NEED_WRAP;
-- }
-- // No more data left to send to the remote peer, so null out the exception field, shutdown and throw
-- // the exception.
-- handshakeException = null;
-- shutdown();
-- throw exception;
+- static void freeBio(long bio) {
+- if (bio != 0) {
+- SSL.freeBIO(bio);
- }
+- }
-
-- // Adding the OpenSslEngine to the OpenSslEngineMap so it can be used in the AbstractCertificateVerifier.
-- engineMap.add(this);
-- if (lastAccessed == -1) {
-- lastAccessed = System.currentTimeMillis();
+- /**
+- * Return the pointer to a <a href="https://www.openssl.org/docs/crypto/BIO_get_mem_ptr.html">in-memory BIO</a>
+- * or {@code 0} if the {@code key} is {@code null}. The BIO contains the content of the {@code key}.
+- */
+- static long toBIO(ByteBufAllocator allocator, PrivateKey key) throws Exception {
+- if (key == null) {
+- return 0;
- }
-
-- if (!certificateSet && keyMaterialManager != null) {
-- certificateSet = true;
-- keyMaterialManager.setKeyMaterial(this);
+- PemEncoded pem = PemPrivateKey.toPEM(allocator, true, key);
+- try {
+- return toBIO(allocator, pem.retain());
+- } finally {
+- pem.release();
- }
+- }
-
-- int code = SSL.doHandshake(ssl);
-- if (code <= 0) {
-- // Check if we have a pending exception that was created during the handshake and if so throw it after
-- // shutdown the connection.
-- if (handshakeException != null) {
-- exception = handshakeException;
-- handshakeException = null;
-- shutdown();
-- throw exception;
-- }
+- /**
+- * Return the pointer to a <a href="https://www.openssl.org/docs/crypto/BIO_get_mem_ptr.html">in-memory BIO</a>
+- * or {@code 0} if the {@code certChain} is {@code null}. The BIO contains the content of the {@code certChain}.
+- */
+- static long toBIO(ByteBufAllocator allocator, X509Certificate... certChain) throws Exception {
+- if (certChain == null) {
+- return 0;
+- }
-
-- int sslError = SSL.getError(ssl, code);
-- if (sslError == SSL.SSL_ERROR_WANT_READ || sslError == SSL.SSL_ERROR_WANT_WRITE) {
-- return pendingStatus(SSL.bioLengthNonApplication(networkBIO));
-- } else {
-- // Everything else is considered as error
-- throw shutdownWithError("SSL_do_handshake");
-- }
+- if (certChain.length == 0) {
+- throw new IllegalArgumentException("certChain can't be empty");
- }
-- // if SSL_do_handshake returns > 0 or sslError == SSL.SSL_ERROR_NAME it means the handshake was finished.
-- session.handshakeFinished();
-- engineMap.remove(ssl);
-- return FINISHED;
-- }
-
-- private SSLEngineResult.HandshakeStatus mayFinishHandshake(SSLEngineResult.HandshakeStatus status)
-- throws SSLException {
-- if (status == NOT_HANDSHAKING && handshakeState != HandshakeState.FINISHED) {
-- // If the status was NOT_HANDSHAKING and we not finished the handshake we need to call
-- // SSL_do_handshake() again
-- return handshake();
+- PemEncoded pem = PemX509Certificate.toPEM(allocator, true, certChain);
+- try {
+- return toBIO(allocator, pem.retain());
+- } finally {
+- pem.release();
- }
-- return status;
- }
-
-- @Override
-- public final synchronized SSLEngineResult.HandshakeStatus getHandshakeStatus() {
-- // Check if we are in the initial handshake phase or shutdown phase
-- return needPendingStatus() ? pendingStatus(SSL.bioLengthNonApplication(networkBIO)) : NOT_HANDSHAKING;
-- }
+- static long toBIO(ByteBufAllocator allocator, PemEncoded pem) throws Exception {
+- try {
+- // We can turn direct buffers straight into BIOs. No need to
+- // make a yet another copy.
+- ByteBuf content = pem.content();
-
-- private SSLEngineResult.HandshakeStatus getHandshakeStatus(int pending) {
-- // Check if we are in the initial handshake phase or shutdown phase
-- return needPendingStatus() ? pendingStatus(pending) : NOT_HANDSHAKING;
+- if (content.isDirect()) {
+- return newBIO(content.retainedSlice());
+- }
+-
+- ByteBuf buffer = allocator.directBuffer(content.readableBytes());
+- try {
+- buffer.writeBytes(content, content.readerIndex(), content.readableBytes());
+- return newBIO(buffer.retainedSlice());
+- } finally {
+- try {
+- // If the contents of the ByteBuf is sensitive (e.g. a PrivateKey) we
+- // need to zero out the bytes of the copy before we're releasing it.
+- if (pem.isSensitive()) {
+- SslUtils.zeroout(buffer);
+- }
+- } finally {
+- buffer.release();
+- }
+- }
+- } finally {
+- pem.release();
+- }
- }
-
-- private boolean needPendingStatus() {
-- return handshakeState != HandshakeState.NOT_STARTED && !isDestroyed()
-- && (handshakeState != HandshakeState.FINISHED || isInboundDone() || isOutboundDone());
+- private static long newBIO(ByteBuf buffer) throws Exception {
+- try {
+- long bio = SSL.newMemBIO();
+- int readable = buffer.readableBytes();
+- if (SSL.bioWrite(bio, OpenSsl.memoryAddress(buffer) + buffer.readerIndex(), readable) != readable) {
+- SSL.freeBIO(bio);
+- throw new IllegalStateException("Could not write data to memory BIO");
+- }
+- return bio;
+- } finally {
+- buffer.release();
+- }
- }
-
- /**
-- * Converts the specified OpenSSL cipher suite to the Java cipher suite.
+- * Returns the {@link OpenSslKeyMaterialProvider} that should be used for OpenSSL. Depending on the given
+- * {@link KeyManagerFactory} this may cache the {@link OpenSslKeyMaterial} for better performance if it can
+- * ensure that the same material is always returned for the same alias.
- */
-- private String toJavaCipherSuite(String openSslCipherSuite) {
-- if (openSslCipherSuite == null) {
-- return null;
+- static OpenSslKeyMaterialProvider providerFor(KeyManagerFactory factory, String password) {
+- if (factory instanceof OpenSslX509KeyManagerFactory) {
+- return ((OpenSslX509KeyManagerFactory) factory).newProvider();
- }
-
-- String prefix = toJavaCipherSuitePrefix(SSL.getVersion(ssl));
-- return CipherSuiteConverter.toJava(openSslCipherSuite, prefix);
+- if (factory instanceof OpenSslCachingX509KeyManagerFactory) {
+- // The user explicit used OpenSslCachingX509KeyManagerFactory which signals us that its fine to cache.
+- return ((OpenSslCachingX509KeyManagerFactory) factory).newProvider(password);
+- }
+- // We can not be sure if the material may change at runtime so we will not cache it.
+- return new OpenSslKeyMaterialProvider(chooseX509KeyManager(factory.getKeyManagers()), password);
- }
-
-- /**
-- * Converts the protocol version string returned by {@link SSL#getVersion(long)} to protocol family string.
-- */
-- private static String toJavaCipherSuitePrefix(String protocolVersion) {
-- final char c;
-- if (protocolVersion == null || protocolVersion.isEmpty()) {
-- c = 0;
-- } else {
-- c = protocolVersion.charAt(0);
+- private static final class PrivateKeyMethod implements SSLPrivateKeyMethod {
+-
+- private final OpenSslEngineMap engineMap;
+- private final OpenSslPrivateKeyMethod keyMethod;
+- PrivateKeyMethod(OpenSslEngineMap engineMap, OpenSslPrivateKeyMethod keyMethod) {
+- this.engineMap = engineMap;
+- this.keyMethod = keyMethod;
- }
-
-- switch (c) {
-- case 'T':
-- return "TLS";
-- case 'S':
-- return "SSL";
-- default:
-- return "UNKNOWN";
+- private ReferenceCountedOpenSslEngine retrieveEngine(long ssl) throws SSLException {
+- ReferenceCountedOpenSslEngine engine = engineMap.get(ssl);
+- if (engine == null) {
+- throw new SSLException("Could not find a " +
+- StringUtil.simpleClassName(ReferenceCountedOpenSslEngine.class) + " for sslPointer " + ssl);
+- }
+- return engine;
- }
-- }
-
-- @Override
-- public final void setUseClientMode(boolean clientMode) {
-- if (clientMode != this.clientMode) {
-- throw new UnsupportedOperationException();
+- @Override
+- public byte[] sign(long ssl, int signatureAlgorithm, byte[] digest) throws Exception {
+- ReferenceCountedOpenSslEngine engine = retrieveEngine(ssl);
+- try {
+- return verifyResult(keyMethod.sign(engine, signatureAlgorithm, digest));
+- } catch (Exception e) {
+- engine.initHandshakeException(e);
+- throw e;
+- }
- }
-- }
-
-- @Override
-- public final boolean getUseClientMode() {
-- return clientMode;
-- }
+- @Override
+- public byte[] decrypt(long ssl, byte[] input) throws Exception {
+- ReferenceCountedOpenSslEngine engine = retrieveEngine(ssl);
+- try {
+- return verifyResult(keyMethod.decrypt(engine, input));
+- } catch (Exception e) {
+- engine.initHandshakeException(e);
+- throw e;
+- }
+- }
-
-- @Override
-- public final void setNeedClientAuth(boolean b) {
-- setClientAuth(b ? ClientAuth.REQUIRE : ClientAuth.NONE);
+- private static byte[] verifyResult(byte[] result) throws SignatureException {
+- if (result == null) {
+- throw new SignatureException();
+- }
+- return result;
+- }
- }
+-}
+diff --git a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngine.java b/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngine.java
+deleted file mode 100644
+index b404a1076b..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngine.java
++++ /dev/null
+@@ -1,2467 +0,0 @@
+-/*
+- * Copyright 2016 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- * http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-package io.netty.handler.ssl;
-
-- @Override
-- public final boolean getNeedClientAuth() {
-- return clientAuth == ClientAuth.REQUIRE;
-- }
+-import io.netty.buffer.ByteBuf;
+-import io.netty.buffer.ByteBufAllocator;
+-import io.netty.internal.tcnative.Buffer;
+-import io.netty.internal.tcnative.SSL;
+-import io.netty.util.AbstractReferenceCounted;
+-import io.netty.util.CharsetUtil;
+-import io.netty.util.ReferenceCounted;
+-import io.netty.util.ResourceLeakDetector;
+-import io.netty.util.ResourceLeakDetectorFactory;
+-import io.netty.util.ResourceLeakTracker;
+-import io.netty.util.internal.EmptyArrays;
+-import io.netty.util.internal.ObjectUtil;
+-import io.netty.util.internal.PlatformDependent;
+-import io.netty.util.internal.StringUtil;
+-import io.netty.util.internal.SuppressJava6Requirement;
+-import io.netty.util.internal.ThrowableUtil;
+-import io.netty.util.internal.UnstableApi;
+-import io.netty.util.internal.logging.InternalLogger;
+-import io.netty.util.internal.logging.InternalLoggerFactory;
-
-- @Override
-- public final void setWantClientAuth(boolean b) {
-- setClientAuth(b ? ClientAuth.OPTIONAL : ClientAuth.NONE);
-- }
+-import java.nio.ByteBuffer;
+-import java.nio.ReadOnlyBufferException;
+-import java.security.Principal;
+-import java.security.cert.Certificate;
+-import java.util.ArrayList;
+-import java.util.Arrays;
+-import java.util.Collection;
+-import java.util.Collections;
+-import java.util.HashMap;
+-import java.util.LinkedHashSet;
+-import java.util.List;
+-import java.util.Map;
+-import java.util.Set;
+-import java.util.concurrent.locks.Lock;
-
-- @Override
-- public final boolean getWantClientAuth() {
-- return clientAuth == ClientAuth.OPTIONAL;
-- }
+-import javax.crypto.spec.SecretKeySpec;
+-import javax.net.ssl.SSLEngine;
+-import javax.net.ssl.SSLEngineResult;
+-import javax.net.ssl.SSLException;
+-import javax.net.ssl.SSLHandshakeException;
+-import javax.net.ssl.SSLParameters;
+-import javax.net.ssl.SSLPeerUnverifiedException;
+-import javax.net.ssl.SSLSession;
+-import javax.net.ssl.SSLSessionBindingEvent;
+-import javax.net.ssl.SSLSessionBindingListener;
+-import javax.net.ssl.SSLSessionContext;
+-import javax.security.cert.X509Certificate;
-
-- /**
-- * See <a href="https://www.openssl.org/docs/man1.0.2/ssl/SSL_set_verify.html">SSL_set_verify</a> and
-- * {@link SSL#setVerify(long, int, int)}.
-- */
-- @UnstableApi
-- public final synchronized void setVerify(int verifyMode, int depth) {
-- SSL.setVerify(ssl, verifyMode, depth);
-- }
+-import static io.netty.handler.ssl.OpenSsl.memoryAddress;
+-import static io.netty.handler.ssl.SslUtils.PROTOCOL_SSL_V2;
+-import static io.netty.handler.ssl.SslUtils.PROTOCOL_SSL_V2_HELLO;
+-import static io.netty.handler.ssl.SslUtils.PROTOCOL_SSL_V3;
+-import static io.netty.handler.ssl.SslUtils.PROTOCOL_TLS_V1;
+-import static io.netty.handler.ssl.SslUtils.PROTOCOL_TLS_V1_1;
+-import static io.netty.handler.ssl.SslUtils.PROTOCOL_TLS_V1_2;
+-import static io.netty.handler.ssl.SslUtils.PROTOCOL_TLS_V1_3;
+-import static io.netty.handler.ssl.SslUtils.SSL_RECORD_HEADER_LENGTH;
+-import static io.netty.util.internal.ObjectUtil.checkNotNull;
+-import static java.lang.Integer.MAX_VALUE;
+-import static java.lang.Math.min;
+-import static javax.net.ssl.SSLEngineResult.HandshakeStatus.FINISHED;
+-import static javax.net.ssl.SSLEngineResult.HandshakeStatus.NEED_TASK;
+-import static javax.net.ssl.SSLEngineResult.HandshakeStatus.NEED_UNWRAP;
+-import static javax.net.ssl.SSLEngineResult.HandshakeStatus.NEED_WRAP;
+-import static javax.net.ssl.SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING;
+-import static javax.net.ssl.SSLEngineResult.Status.BUFFER_OVERFLOW;
+-import static javax.net.ssl.SSLEngineResult.Status.BUFFER_UNDERFLOW;
+-import static javax.net.ssl.SSLEngineResult.Status.CLOSED;
+-import static javax.net.ssl.SSLEngineResult.Status.OK;
-
-- private void setClientAuth(ClientAuth mode) {
-- if (clientMode) {
-- return;
-- }
-- synchronized (this) {
-- if (clientAuth == mode) {
-- // No need to issue any JNI calls if the mode is the same
-- return;
-- }
-- switch (mode) {
-- case NONE:
-- SSL.setVerify(ssl, SSL.SSL_CVERIFY_NONE, ReferenceCountedOpenSslContext.VERIFY_DEPTH);
-- break;
-- case REQUIRE:
-- SSL.setVerify(ssl, SSL.SSL_CVERIFY_REQUIRED, ReferenceCountedOpenSslContext.VERIFY_DEPTH);
-- break;
-- case OPTIONAL:
-- SSL.setVerify(ssl, SSL.SSL_CVERIFY_OPTIONAL, ReferenceCountedOpenSslContext.VERIFY_DEPTH);
-- break;
-- default:
-- throw new Error(mode.toString());
-- }
-- clientAuth = mode;
-- }
-- }
+-/**
+- * Implements a {@link SSLEngine} using
+- * <a href="https://www.openssl.org/docs/crypto/BIO_s_bio.html#EXAMPLE">OpenSSL BIO abstractions</a>.
+- * <p>Instances of this class must be {@link #release() released} or else native memory will leak!
+- *
+- * <p>Instances of this class <strong>must</strong> be released before the {@link ReferenceCountedOpenSslContext}
+- * the instance depends upon are released. Otherwise if any method of this class is called which uses the
+- * the {@link ReferenceCountedOpenSslContext} JNI resources the JVM may crash.
+- */
+-public class ReferenceCountedOpenSslEngine extends SSLEngine implements ReferenceCounted, ApplicationProtocolAccessor {
-
-- @Override
-- public final void setEnableSessionCreation(boolean b) {
-- if (b) {
-- throw new UnsupportedOperationException();
-- }
-- }
+- private static final InternalLogger logger = InternalLoggerFactory.getInstance(ReferenceCountedOpenSslEngine.class);
-
-- @Override
-- public final boolean getEnableSessionCreation() {
-- return false;
-- }
+- private static final ResourceLeakDetector<ReferenceCountedOpenSslEngine> leakDetector =
+- ResourceLeakDetectorFactory.instance().newResourceLeakDetector(ReferenceCountedOpenSslEngine.class);
+- private static final int OPENSSL_OP_NO_PROTOCOL_INDEX_SSLV2 = 0;
+- private static final int OPENSSL_OP_NO_PROTOCOL_INDEX_SSLV3 = 1;
+- private static final int OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1 = 2;
+- private static final int OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_1 = 3;
+- private static final int OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_2 = 4;
+- private static final int OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_3 = 5;
+- private static final int[] OPENSSL_OP_NO_PROTOCOLS = {
+- SSL.SSL_OP_NO_SSLv2,
+- SSL.SSL_OP_NO_SSLv3,
+- SSL.SSL_OP_NO_TLSv1,
+- SSL.SSL_OP_NO_TLSv1_1,
+- SSL.SSL_OP_NO_TLSv1_2,
+- SSL.SSL_OP_NO_TLSv1_3
+- };
-
-- @Override
-- public final synchronized SSLParameters getSSLParameters() {
-- SSLParameters sslParameters = super.getSSLParameters();
+- /**
+- * Depends upon tcnative ... only use if tcnative is available!
+- */
+- static final int MAX_PLAINTEXT_LENGTH = SSL.SSL_MAX_PLAINTEXT_LENGTH;
+- /**
+- * Depends upon tcnative ... only use if tcnative is available!
+- */
+- private static final int MAX_RECORD_SIZE = SSL.SSL_MAX_RECORD_LENGTH;
-
-- int version = PlatformDependent.javaVersion();
-- if (version >= 7) {
-- sslParameters.setEndpointIdentificationAlgorithm(endPointIdentificationAlgorithm);
-- Java7SslParametersUtils.setAlgorithmConstraints(sslParameters, algorithmConstraints);
-- if (version >= 8) {
-- if (sniHostNames != null) {
-- Java8SslUtils.setSniHostNames(sslParameters, sniHostNames);
-- }
-- if (!isDestroyed()) {
-- Java8SslUtils.setUseCipherSuitesOrder(
-- sslParameters, (SSL.getOptions(ssl) & SSL.SSL_OP_CIPHER_SERVER_PREFERENCE) != 0);
-- }
+- private static final SSLEngineResult NEED_UNWRAP_OK = new SSLEngineResult(OK, NEED_UNWRAP, 0, 0);
+- private static final SSLEngineResult NEED_UNWRAP_CLOSED = new SSLEngineResult(CLOSED, NEED_UNWRAP, 0, 0);
+- private static final SSLEngineResult NEED_WRAP_OK = new SSLEngineResult(OK, NEED_WRAP, 0, 0);
+- private static final SSLEngineResult NEED_WRAP_CLOSED = new SSLEngineResult(CLOSED, NEED_WRAP, 0, 0);
+- private static final SSLEngineResult CLOSED_NOT_HANDSHAKING = new SSLEngineResult(CLOSED, NOT_HANDSHAKING, 0, 0);
-
-- Java8SslUtils.setSNIMatchers(sslParameters, matchers);
-- }
-- }
-- return sslParameters;
+- // OpenSSL state
+- private long ssl;
+- private long networkBIO;
+-
+- private enum HandshakeState {
+- /**
+- * Not started yet.
+- */
+- NOT_STARTED,
+- /**
+- * Started via unwrap/wrap.
+- */
+- STARTED_IMPLICITLY,
+- /**
+- * Started via {@link #beginHandshake()}.
+- */
+- STARTED_EXPLICITLY,
+- /**
+- * Handshake is finished.
+- */
+- FINISHED
- }
-
-- @Override
-- public final synchronized void setSSLParameters(SSLParameters sslParameters) {
-- int version = PlatformDependent.javaVersion();
-- if (version >= 7) {
-- if (sslParameters.getAlgorithmConstraints() != null) {
-- throw new IllegalArgumentException("AlgorithmConstraints are not supported.");
-- }
+- private HandshakeState handshakeState = HandshakeState.NOT_STARTED;
+- private boolean receivedShutdown;
+- private volatile boolean destroyed;
+- private volatile String applicationProtocol;
+- private volatile boolean needTask;
-
-- if (version >= 8) {
-- if (!isDestroyed()) {
-- if (clientMode) {
-- final List<String> sniHostNames = Java8SslUtils.getSniHostNames(sslParameters);
-- for (String name: sniHostNames) {
-- SSL.setTlsExtHostName(ssl, name);
-- }
-- this.sniHostNames = sniHostNames;
-- }
-- if (Java8SslUtils.getUseCipherSuitesOrder(sslParameters)) {
-- SSL.setOptions(ssl, SSL.SSL_OP_CIPHER_SERVER_PREFERENCE);
-- } else {
-- SSL.clearOptions(ssl, SSL.SSL_OP_CIPHER_SERVER_PREFERENCE);
-- }
-- }
-- matchers = sslParameters.getSNIMatchers();
+- // Reference Counting
+- private final ResourceLeakTracker<ReferenceCountedOpenSslEngine> leak;
+- private final AbstractReferenceCounted refCnt = new AbstractReferenceCounted() {
+- @Override
+- public ReferenceCounted touch(Object hint) {
+- if (leak != null) {
+- leak.record(hint);
- }
-
-- final String endPointIdentificationAlgorithm = sslParameters.getEndpointIdentificationAlgorithm();
-- final boolean endPointVerificationEnabled = endPointIdentificationAlgorithm != null &&
-- !endPointIdentificationAlgorithm.isEmpty();
-- SSL.setHostNameValidation(ssl, DEFAULT_HOSTNAME_VALIDATION_FLAGS,
-- endPointVerificationEnabled ? getPeerHost() : null);
-- // If the user asks for hostname verification we must ensure we verify the peer.
-- // If the user disables hostname verification we leave it up to the user to change the mode manually.
-- if (clientMode && endPointVerificationEnabled) {
-- SSL.setVerify(ssl, SSL.SSL_CVERIFY_REQUIRED, -1);
-- }
+- return ReferenceCountedOpenSslEngine.this;
+- }
-
-- this.endPointIdentificationAlgorithm = endPointIdentificationAlgorithm;
-- algorithmConstraints = sslParameters.getAlgorithmConstraints();
+- @Override
+- protected void deallocate() {
+- shutdown();
+- if (leak != null) {
+- boolean closed = leak.close(ReferenceCountedOpenSslEngine.this);
+- assert closed;
+- }
+- parentContext.release();
- }
-- super.setSSLParameters(sslParameters);
-- }
+- };
-
-- private boolean isDestroyed() {
-- return destroyed != 0;
-- }
+- private volatile ClientAuth clientAuth = ClientAuth.NONE;
+- private volatile Certificate[] localCertificateChain;
-
-- static int calculateOutNetBufSize(int pendingBytes, int numComponents) {
-- return (int) min(MAX_ENCRYPTED_PACKET_LENGTH,
-- pendingBytes + (long) MAX_TLS_RECORD_OVERHEAD_LENGTH * numComponents);
-- }
+- // Updated once a new handshake is started and so the SSLSession reused.
+- private volatile long lastAccessed = -1;
-
-- final boolean checkSniHostnameMatch(String hostname) {
-- return Java8SslUtils.checkSniHostnameMatch(matchers, hostname);
-- }
+- private String endPointIdentificationAlgorithm;
+- // Store as object as AlgorithmConstraints only exists since java 7.
+- private Object algorithmConstraints;
+- private List<String> sniHostNames;
-
-- private final class OpenSslSession implements SSLSession, ApplicationProtocolAccessor {
-- private final OpenSslSessionContext sessionContext;
+- // Mark as volatile as accessed by checkSniHostnameMatch(...) and also not specify the SNIMatcher type to allow us
+- // using it with java7.
+- private volatile Collection<?> matchers;
-
-- // These are guarded by synchronized(OpenSslEngine.this) as handshakeFinished() may be triggered by any
-- // thread.
-- private X509Certificate[] x509PeerCerts;
-- private Certificate[] peerCerts;
-- private String protocol;
-- private String applicationProtocol;
-- private String cipher;
-- private byte[] id;
-- private long creationTime;
+- // SSL Engine status variables
+- private boolean isInboundDone;
+- private boolean outboundClosed;
-
-- // lazy init for memory reasons
-- private Map<String, Object> values;
+- final boolean jdkCompatibilityMode;
+- private final boolean clientMode;
+- final ByteBufAllocator alloc;
+- private final OpenSslEngineMap engineMap;
+- private final OpenSslApplicationProtocolNegotiator apn;
+- private final ReferenceCountedOpenSslContext parentContext;
+- private final OpenSslSession session;
+- private final ByteBuffer[] singleSrcBuffer = new ByteBuffer[1];
+- private final ByteBuffer[] singleDstBuffer = new ByteBuffer[1];
+- private final boolean enableOcsp;
+- private int maxWrapOverhead;
+- private int maxWrapBufferSize;
+- private Throwable pendingException;
-
-- OpenSslSession(OpenSslSessionContext sessionContext) {
-- this.sessionContext = sessionContext;
-- }
+- /**
+- * Create a new instance.
+- * @param context Reference count release responsibility is not transferred! The callee still owns this object.
+- * @param alloc The allocator to use.
+- * @param peerHost The peer host name.
+- * @param peerPort The peer port.
+- * @param jdkCompatibilityMode {@code true} to behave like described in
+- * https://docs.oracle.com/javase/7/docs/api/javax/net/ssl/SSLEngine.html.
+- * {@code false} allows for partial and/or multiple packets to be process in a single
+- * wrap or unwrap call.
+- * @param leakDetection {@code true} to enable leak detection of this object.
+- */
+- ReferenceCountedOpenSslEngine(ReferenceCountedOpenSslContext context, final ByteBufAllocator alloc, String peerHost,
+- int peerPort, boolean jdkCompatibilityMode, boolean leakDetection) {
+- super(peerHost, peerPort);
+- OpenSsl.ensureAvailability();
+- this.alloc = checkNotNull(alloc, "alloc");
+- apn = (OpenSslApplicationProtocolNegotiator) context.applicationProtocolNegotiator();
+- clientMode = context.isClient();
+- if (PlatformDependent.javaVersion() >= 7) {
+- session = new ExtendedOpenSslSession(new DefaultOpenSslSession(context.sessionContext())) {
+- private String[] peerSupportedSignatureAlgorithms;
+- private List requestedServerNames;
-
-- @Override
-- public byte[] getId() {
-- synchronized (ReferenceCountedOpenSslEngine.this) {
-- if (id == null) {
-- return EmptyArrays.EMPTY_BYTES;
+- @Override
+- public List getRequestedServerNames() {
+- if (clientMode) {
+- return Java8SslUtils.getSniHostNames(sniHostNames);
+- } else {
+- synchronized (ReferenceCountedOpenSslEngine.this) {
+- if (requestedServerNames == null) {
+- if (isDestroyed()) {
+- requestedServerNames = Collections.emptyList();
+- } else {
+- String name = SSL.getSniHostname(ssl);
+- if (name == null) {
+- requestedServerNames = Collections.emptyList();
+- } else {
+- // Convert to bytes as we do not want to do any strict validation of the
+- // SNIHostName while creating it.
+- requestedServerNames =
+- Java8SslUtils.getSniHostName(
+- SSL.getSniHostname(ssl).getBytes(CharsetUtil.UTF_8));
+- }
+- }
+- }
+- return requestedServerNames;
+- }
+- }
- }
-- return id.clone();
-- }
-- }
-
-- @Override
-- public SSLSessionContext getSessionContext() {
-- return sessionContext;
-- }
+- @Override
+- public String[] getPeerSupportedSignatureAlgorithms() {
+- synchronized (ReferenceCountedOpenSslEngine.this) {
+- if (peerSupportedSignatureAlgorithms == null) {
+- if (isDestroyed()) {
+- peerSupportedSignatureAlgorithms = EmptyArrays.EMPTY_STRINGS;
+- } else {
+- String[] algs = SSL.getSigAlgs(ssl);
+- if (algs == null) {
+- peerSupportedSignatureAlgorithms = EmptyArrays.EMPTY_STRINGS;
+- } else {
+- Set<String> algorithmList = new LinkedHashSet<String>(algs.length);
+- for (String alg: algs) {
+- String converted = SignatureAlgorithmConverter.toJavaName(alg);
-
-- @Override
-- public long getCreationTime() {
-- synchronized (ReferenceCountedOpenSslEngine.this) {
-- if (creationTime == 0 && !isDestroyed()) {
-- creationTime = SSL.getTime(ssl) * 1000L;
+- if (converted != null) {
+- algorithmList.add(converted);
+- }
+- }
+- peerSupportedSignatureAlgorithms = algorithmList.toArray(new String[0]);
+- }
+- }
+- }
+- return peerSupportedSignatureAlgorithms.clone();
+- }
- }
-- }
-- return creationTime;
-- }
--
-- @Override
-- public long getLastAccessedTime() {
-- long lastAccessed = ReferenceCountedOpenSslEngine.this.lastAccessed;
-- // if lastAccessed is -1 we will just return the creation time as the handshake was not started yet.
-- return lastAccessed == -1 ? getCreationTime() : lastAccessed;
-- }
-
-- @Override
-- public void invalidate() {
-- synchronized (ReferenceCountedOpenSslEngine.this) {
-- if (!isDestroyed()) {
-- SSL.setTimeout(ssl, 0);
+- @Override
+- public List<byte[]> getStatusResponses() {
+- byte[] ocspResponse = null;
+- if (enableOcsp && clientMode) {
+- synchronized (ReferenceCountedOpenSslEngine.this) {
+- if (!isDestroyed()) {
+- ocspResponse = SSL.getOcspResponse(ssl);
+- }
+- }
+- }
+- return ocspResponse == null ?
+- Collections.<byte[]>emptyList() : Collections.singletonList(ocspResponse);
- }
-- }
+- };
+- } else {
+- session = new DefaultOpenSslSession(context.sessionContext());
- }
--
-- @Override
-- public boolean isValid() {
-- synchronized (ReferenceCountedOpenSslEngine.this) {
-- if (!isDestroyed()) {
-- return System.currentTimeMillis() - (SSL.getTimeout(ssl) * 1000L) < (SSL.getTime(ssl) * 1000L);
-- }
-- }
-- return false;
+- engineMap = context.engineMap;
+- enableOcsp = context.enableOcsp;
+- if (!context.sessionContext().useKeyManager()) {
+- // If we do not use the KeyManagerFactory we need to set localCertificateChain now.
+- // When we use a KeyManagerFactory it will be set during setKeyMaterial(...).
+- localCertificateChain = context.keyCertChain;
- }
-
-- @Override
-- public void putValue(String name, Object value) {
-- if (name == null) {
-- throw new NullPointerException("name");
-- }
-- if (value == null) {
-- throw new NullPointerException("value");
-- }
-- Map<String, Object> values = this.values;
-- if (values == null) {
-- // Use size of 2 to keep the memory overhead small
-- values = this.values = new HashMap<String, Object>(2);
-- }
-- Object old = values.put(name, value);
-- if (value instanceof SSLSessionBindingListener) {
-- ((SSLSessionBindingListener) value).valueBound(new SSLSessionBindingEvent(this, name));
-- }
-- notifyUnbound(old, name);
+- this.jdkCompatibilityMode = jdkCompatibilityMode;
+- Lock readerLock = context.ctxLock.readLock();
+- readerLock.lock();
+- final long finalSsl;
+- try {
+- finalSsl = SSL.newSSL(context.ctx, !context.isClient());
+- } finally {
+- readerLock.unlock();
- }
+- synchronized (this) {
+- ssl = finalSsl;
+- try {
+- networkBIO = SSL.bioNewByteBuffer(ssl, context.getBioNonApplicationBufferSize());
-
-- @Override
-- public Object getValue(String name) {
-- if (name == null) {
-- throw new NullPointerException("name");
-- }
-- if (values == null) {
-- return null;
-- }
-- return values.get(name);
-- }
+- // Set the client auth mode, this needs to be done via setClientAuth(...) method so we actually call the
+- // needed JNI methods.
+- setClientAuth(clientMode ? ClientAuth.NONE : context.clientAuth);
-
-- @Override
-- public void removeValue(String name) {
-- if (name == null) {
-- throw new NullPointerException("name");
-- }
-- Map<String, Object> values = this.values;
-- if (values == null) {
-- return;
-- }
-- Object old = values.remove(name);
-- notifyUnbound(old, name);
-- }
+- if (context.protocols != null) {
+- setEnabledProtocols(context.protocols);
+- }
-
-- @Override
-- public String[] getValueNames() {
-- Map<String, Object> values = this.values;
-- if (values == null || values.isEmpty()) {
-- return EmptyArrays.EMPTY_STRINGS;
-- }
-- return values.keySet().toArray(new String[values.size()]);
-- }
+- // Use SNI if peerHost was specified and a valid hostname
+- // See https://github.com/netty/netty/issues/4746
+- if (clientMode && SslUtils.isValidHostNameForSNI(peerHost)) {
+- SSL.setTlsExtHostName(ssl, peerHost);
+- sniHostNames = Collections.singletonList(peerHost);
+- }
-
-- private void notifyUnbound(Object value, String name) {
-- if (value instanceof SSLSessionBindingListener) {
-- ((SSLSessionBindingListener) value).valueUnbound(new SSLSessionBindingEvent(this, name));
-- }
-- }
+- if (enableOcsp) {
+- SSL.enableOcsp(ssl);
+- }
-
-- /**
-- * Finish the handshake and so init everything in the {@link OpenSslSession} that should be accessible by
-- * the user.
-- */
-- void handshakeFinished() throws SSLException {
-- synchronized (ReferenceCountedOpenSslEngine.this) {
-- if (!isDestroyed()) {
-- id = SSL.getSessionId(ssl);
-- cipher = toJavaCipherSuite(SSL.getCipherForSSL(ssl));
-- protocol = SSL.getVersion(ssl);
+- if (!jdkCompatibilityMode) {
+- SSL.setMode(ssl, SSL.getMode(ssl) | SSL.SSL_MODE_ENABLE_PARTIAL_WRITE);
+- }
-
-- initPeerCerts();
-- selectApplicationProtocol();
+- // setMode may impact the overhead.
+- calculateMaxWrapOverhead();
+- } catch (Throwable cause) {
+- // Call shutdown so we are sure we correctly release all native memory and also guard against the
+- // case when shutdown() will be called by the finalizer again.
+- shutdown();
-
-- handshakeState = HandshakeState.FINISHED;
-- } else {
-- throw new SSLException("Already closed");
-- }
+- PlatformDependent.throwException(cause);
- }
- }
-
-- /**
-- * Init peer certificates that can be obtained via {@link #getPeerCertificateChain()}
-- * and {@link #getPeerCertificates()}.
-- */
-- private void initPeerCerts() {
-- // Return the full chain from the JNI layer.
-- byte[][] chain = SSL.getPeerCertChain(ssl);
-- if (clientMode) {
-- if (isEmpty(chain)) {
-- peerCerts = EMPTY_CERTIFICATES;
-- x509PeerCerts = EMPTY_JAVAX_X509_CERTIFICATES;
-- } else {
-- peerCerts = new Certificate[chain.length];
-- x509PeerCerts = new X509Certificate[chain.length];
-- initCerts(chain, 0);
-- }
-- } else {
-- // if used on the server side SSL_get_peer_cert_chain(...) will not include the remote peer
-- // certificate. We use SSL_get_peer_certificate to get it in this case and add it to our
-- // array later.
-- //
-- // See https://www.openssl.org/docs/ssl/SSL_get_peer_cert_chain.html
-- byte[] clientCert = SSL.getPeerCertificate(ssl);
-- if (isEmpty(clientCert)) {
-- peerCerts = EMPTY_CERTIFICATES;
-- x509PeerCerts = EMPTY_JAVAX_X509_CERTIFICATES;
-- } else {
-- if (isEmpty(chain)) {
-- peerCerts = new Certificate[] {new OpenSslX509Certificate(clientCert)};
-- x509PeerCerts = new X509Certificate[] {new OpenSslJavaxX509Certificate(clientCert)};
-- } else {
-- peerCerts = new Certificate[chain.length + 1];
-- x509PeerCerts = new X509Certificate[chain.length + 1];
-- peerCerts[0] = new OpenSslX509Certificate(clientCert);
-- x509PeerCerts[0] = new OpenSslJavaxX509Certificate(clientCert);
-- initCerts(chain, 1);
-- }
-- }
-- }
+- // Now that everything looks good and we're going to successfully return the
+- // object so we need to retain a reference to the parent context.
+- parentContext = context;
+- parentContext.retain();
+-
+- // Only create the leak after everything else was executed and so ensure we don't produce a false-positive for
+- // the ResourceLeakDetector.
+- leak = leakDetection ? leakDetector.track(this) : null;
+- }
+-
+- final synchronized String[] authMethods() {
+- if (isDestroyed()) {
+- return EmptyArrays.EMPTY_STRINGS;
- }
+- return SSL.authenticationMethods(ssl);
+- }
-
-- private void initCerts(byte[][] chain, int startPos) {
-- for (int i = 0; i < chain.length; i++) {
-- int certPos = startPos + i;
-- peerCerts[certPos] = new OpenSslX509Certificate(chain[i]);
-- x509PeerCerts[certPos] = new OpenSslJavaxX509Certificate(chain[i]);
+- final boolean setKeyMaterial(OpenSslKeyMaterial keyMaterial) throws Exception {
+- synchronized (this) {
+- if (isDestroyed()) {
+- return false;
- }
+- SSL.setKeyMaterial(ssl, keyMaterial.certificateChainAddress(), keyMaterial.privateKeyAddress());
- }
+- localCertificateChain = keyMaterial.certificateChain();
+- return true;
+- }
-
-- /**
-- * Select the application protocol used.
-- */
-- private void selectApplicationProtocol() throws SSLException {
-- ApplicationProtocolConfig.SelectedListenerFailureBehavior behavior = apn.selectedListenerFailureBehavior();
-- List<String> protocols = apn.protocols();
-- String applicationProtocol;
-- switch (apn.protocol()) {
-- case NONE:
-- break;
-- // We always need to check for applicationProtocol == null as the remote peer may not support
-- // the TLS extension or may have returned an empty selection.
-- case ALPN:
-- applicationProtocol = SSL.getAlpnSelected(ssl);
-- if (applicationProtocol != null) {
-- this.applicationProtocol = selectApplicationProtocol(
-- protocols, behavior, applicationProtocol);
-- }
-- break;
-- case NPN:
-- applicationProtocol = SSL.getNextProtoNegotiated(ssl);
-- if (applicationProtocol != null) {
-- this.applicationProtocol = selectApplicationProtocol(
-- protocols, behavior, applicationProtocol);
-- }
-- break;
-- case NPN_AND_ALPN:
-- applicationProtocol = SSL.getAlpnSelected(ssl);
-- if (applicationProtocol == null) {
-- applicationProtocol = SSL.getNextProtoNegotiated(ssl);
-- }
-- if (applicationProtocol != null) {
-- this.applicationProtocol = selectApplicationProtocol(
-- protocols, behavior, applicationProtocol);
-- }
-- break;
-- default:
-- throw new Error();
-- }
+- final synchronized SecretKeySpec masterKey() {
+- if (isDestroyed()) {
+- return null;
- }
+- return new SecretKeySpec(SSL.getMasterKey(ssl), "AES");
+- }
-
-- private String selectApplicationProtocol(List<String> protocols,
-- ApplicationProtocolConfig.SelectedListenerFailureBehavior behavior,
-- String applicationProtocol) throws SSLException {
-- if (behavior == ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT) {
-- return applicationProtocol;
-- } else {
-- int size = protocols.size();
-- assert size > 0;
-- if (protocols.contains(applicationProtocol)) {
-- return applicationProtocol;
-- } else {
-- if (behavior == ApplicationProtocolConfig.SelectedListenerFailureBehavior.CHOOSE_MY_LAST_PROTOCOL) {
-- return protocols.get(size - 1);
-- } else {
-- throw new SSLException("unknown protocol " + applicationProtocol);
-- }
-- }
+- /**
+- * Sets the OCSP response.
+- */
+- @UnstableApi
+- public void setOcspResponse(byte[] response) {
+- if (!enableOcsp) {
+- throw new IllegalStateException("OCSP stapling is not enabled");
+- }
+-
+- if (clientMode) {
+- throw new IllegalStateException("Not a server SSLEngine");
+- }
+-
+- synchronized (this) {
+- if (!isDestroyed()) {
+- SSL.setOcspResponse(ssl, response);
- }
- }
+- }
-
-- @Override
-- public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException {
-- synchronized (ReferenceCountedOpenSslEngine.this) {
-- if (isEmpty(peerCerts)) {
-- throw new SSLPeerUnverifiedException("peer not verified");
-- }
-- return peerCerts.clone();
+- /**
+- * Returns the OCSP response or {@code null} if the server didn't provide a stapled OCSP response.
+- */
+- @UnstableApi
+- public byte[] getOcspResponse() {
+- if (!enableOcsp) {
+- throw new IllegalStateException("OCSP stapling is not enabled");
+- }
+-
+- if (!clientMode) {
+- throw new IllegalStateException("Not a client SSLEngine");
+- }
+-
+- synchronized (this) {
+- if (isDestroyed()) {
+- return EmptyArrays.EMPTY_BYTES;
- }
+- return SSL.getOcspResponse(ssl);
- }
+- }
-
-- @Override
-- public Certificate[] getLocalCertificates() {
-- if (localCerts == null) {
+- @Override
+- public final int refCnt() {
+- return refCnt.refCnt();
+- }
+-
+- @Override
+- public final ReferenceCounted retain() {
+- refCnt.retain();
+- return this;
+- }
+-
+- @Override
+- public final ReferenceCounted retain(int increment) {
+- refCnt.retain(increment);
+- return this;
+- }
+-
+- @Override
+- public final ReferenceCounted touch() {
+- refCnt.touch();
+- return this;
+- }
+-
+- @Override
+- public final ReferenceCounted touch(Object hint) {
+- refCnt.touch(hint);
+- return this;
+- }
+-
+- @Override
+- public final boolean release() {
+- return refCnt.release();
+- }
+-
+- @Override
+- public final boolean release(int decrement) {
+- return refCnt.release(decrement);
+- }
+-
+- @Override
+- public final synchronized SSLSession getHandshakeSession() {
+- // Javadocs state return value should be:
+- // null if this instance is not currently handshaking, or if the current handshake has not
+- // progressed far enough to create a basic SSLSession. Otherwise, this method returns the
+- // SSLSession currently being negotiated.
+- switch(handshakeState) {
+- case NOT_STARTED:
+- case FINISHED:
- return null;
-- }
-- return localCerts.clone();
+- default:
+- return session;
- }
+- }
-
-- @Override
-- public X509Certificate[] getPeerCertificateChain() throws SSLPeerUnverifiedException {
-- synchronized (ReferenceCountedOpenSslEngine.this) {
-- if (isEmpty(x509PeerCerts)) {
-- throw new SSLPeerUnverifiedException("peer not verified");
+- /**
+- * Returns the pointer to the {@code SSL} object for this {@link ReferenceCountedOpenSslEngine}.
+- * Be aware that it is freed as soon as the {@link #release()} or {@link #shutdown()} methods are called.
+- * At this point {@code 0} will be returned.
+- */
+- public final synchronized long sslPointer() {
+- return ssl;
+- }
+-
+- /**
+- * Destroys this engine.
+- */
+- public final synchronized void shutdown() {
+- if (!destroyed) {
+- destroyed = true;
+- engineMap.remove(ssl);
+- SSL.freeSSL(ssl);
+- ssl = networkBIO = 0;
+-
+- isInboundDone = outboundClosed = true;
+- }
+-
+- // On shutdown clear all errors
+- SSL.clearError();
+- }
+-
+- /**
+- * Write plaintext data to the OpenSSL internal BIO
+- *
+- * Calling this function with src.remaining == 0 is undefined.
+- */
+- private int writePlaintextData(final ByteBuffer src, int len) {
+- final int pos = src.position();
+- final int limit = src.limit();
+- final int sslWrote;
+-
+- if (src.isDirect()) {
+- sslWrote = SSL.writeToSSL(ssl, bufferAddress(src) + pos, len);
+- if (sslWrote > 0) {
+- src.position(pos + sslWrote);
+- }
+- } else {
+- ByteBuf buf = alloc.directBuffer(len);
+- try {
+- src.limit(pos + len);
+-
+- buf.setBytes(0, src);
+- src.limit(limit);
+-
+- sslWrote = SSL.writeToSSL(ssl, memoryAddress(buf), len);
+- if (sslWrote > 0) {
+- src.position(pos + sslWrote);
+- } else {
+- src.position(pos);
- }
-- return x509PeerCerts.clone();
+- } finally {
+- buf.release();
- }
- }
+- return sslWrote;
+- }
-
-- @Override
-- public Principal getPeerPrincipal() throws SSLPeerUnverifiedException {
-- Certificate[] peer = getPeerCertificates();
-- // No need for null or length > 0 is needed as this is done in getPeerCertificates()
-- // already.
-- return ((java.security.cert.X509Certificate) peer[0]).getSubjectX500Principal();
-- }
+- /**
+- * Write encrypted data to the OpenSSL network BIO.
+- */
+- private ByteBuf writeEncryptedData(final ByteBuffer src, int len) {
+- final int pos = src.position();
+- if (src.isDirect()) {
+- SSL.bioSetByteBuffer(networkBIO, bufferAddress(src) + pos, len, false);
+- } else {
+- final ByteBuf buf = alloc.directBuffer(len);
+- try {
+- final int limit = src.limit();
+- src.limit(pos + len);
+- buf.writeBytes(src);
+- // Restore the original position and limit because we don't want to consume from `src`.
+- src.position(pos);
+- src.limit(limit);
-
-- @Override
-- public Principal getLocalPrincipal() {
-- Certificate[] local = localCerts;
-- if (local == null || local.length == 0) {
-- return null;
+- SSL.bioSetByteBuffer(networkBIO, memoryAddress(buf), len, false);
+- return buf;
+- } catch (Throwable cause) {
+- buf.release();
+- PlatformDependent.throwException(cause);
- }
-- return ((java.security.cert.X509Certificate) local[0]).getIssuerX500Principal();
- }
+- return null;
+- }
-
-- @Override
-- public String getCipherSuite() {
-- synchronized (ReferenceCountedOpenSslEngine.this) {
-- if (cipher == null) {
-- return INVALID_CIPHER;
-- }
-- return cipher;
+- /**
+- * Read plaintext data from the OpenSSL internal BIO
+- */
+- private int readPlaintextData(final ByteBuffer dst) {
+- final int sslRead;
+- final int pos = dst.position();
+- if (dst.isDirect()) {
+- sslRead = SSL.readFromSSL(ssl, bufferAddress(dst) + pos, dst.limit() - pos);
+- if (sslRead > 0) {
+- dst.position(pos + sslRead);
- }
-- }
--
-- @Override
-- public String getProtocol() {
-- String protocol = this.protocol;
-- if (protocol == null) {
-- synchronized (ReferenceCountedOpenSslEngine.this) {
-- if (!isDestroyed()) {
-- protocol = SSL.getVersion(ssl);
-- } else {
-- protocol = StringUtil.EMPTY_STRING;
-- }
+- } else {
+- final int limit = dst.limit();
+- final int len = min(maxEncryptedPacketLength0(), limit - pos);
+- final ByteBuf buf = alloc.directBuffer(len);
+- try {
+- sslRead = SSL.readFromSSL(ssl, memoryAddress(buf), len);
+- if (sslRead > 0) {
+- dst.limit(pos + sslRead);
+- buf.getBytes(buf.readerIndex(), dst);
+- dst.limit(limit);
- }
+- } finally {
+- buf.release();
- }
-- return protocol;
-- }
--
-- @Override
-- public String getApplicationProtocol() {
-- synchronized (ReferenceCountedOpenSslEngine.this) {
-- return applicationProtocol;
-- }
-- }
--
-- @Override
-- public String getPeerHost() {
-- return ReferenceCountedOpenSslEngine.this.getPeerHost();
- }
-
-- @Override
-- public int getPeerPort() {
-- return ReferenceCountedOpenSslEngine.this.getPeerPort();
-- }
+- return sslRead;
+- }
-
-- @Override
-- public int getPacketBufferSize() {
-- return MAX_ENCRYPTED_PACKET_LENGTH;
-- }
+- /**
+- * Visible only for testing!
+- */
+- final synchronized int maxWrapOverhead() {
+- return maxWrapOverhead;
+- }
-
-- @Override
-- public int getApplicationBufferSize() {
-- return MAX_PLAINTEXT_LENGTH;
-- }
+- /**
+- * Visible only for testing!
+- */
+- final synchronized int maxEncryptedPacketLength() {
+- return maxEncryptedPacketLength0();
- }
--}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslServerContext.java b/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslServerContext.java
-deleted file mode 100644
-index 4c9df31..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslServerContext.java
-+++ /dev/null
-@@ -1,239 +0,0 @@
--/*
-- * Copyright 2016 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
-
--import io.netty.internal.tcnative.SSL;
--import io.netty.internal.tcnative.SSLContext;
--import io.netty.internal.tcnative.SniHostNameMatcher;
--import io.netty.util.internal.PlatformDependent;
--import io.netty.util.internal.logging.InternalLogger;
--import io.netty.util.internal.logging.InternalLoggerFactory;
+- /**
+- * This method is intentionally not synchronized, only use if you know you are in the EventLoop
+- * thread and visibility on {@link #maxWrapOverhead} is achieved via other synchronized blocks.
+- */
+- final int maxEncryptedPacketLength0() {
+- return maxWrapOverhead + MAX_PLAINTEXT_LENGTH;
+- }
-
--import java.security.KeyStore;
--import java.security.PrivateKey;
--import java.security.cert.X509Certificate;
--import javax.net.ssl.KeyManagerFactory;
--import javax.net.ssl.SSLException;
--import javax.net.ssl.TrustManagerFactory;
--import javax.net.ssl.X509ExtendedKeyManager;
--import javax.net.ssl.X509ExtendedTrustManager;
--import javax.net.ssl.X509KeyManager;
--import javax.net.ssl.X509TrustManager;
+- /**
+- * This method is intentionally not synchronized, only use if you know you are in the EventLoop
+- * thread and visibility on {@link #maxWrapBufferSize} and {@link #maxWrapOverhead} is achieved
+- * via other synchronized blocks.
+- */
+- final int calculateMaxLengthForWrap(int plaintextLength, int numComponents) {
+- return (int) min(maxWrapBufferSize, plaintextLength + (long) maxWrapOverhead * numComponents);
+- }
-
--import static io.netty.util.internal.ObjectUtil.checkNotNull;
+- final synchronized int sslPending() {
+- return sslPending0();
+- }
-
--/**
-- * A server-side {@link SslContext} which uses OpenSSL's SSL/TLS implementation.
-- * <p>Instances of this class must be {@link #release() released} or else native memory will leak!
-- *
-- * <p>Instances of this class <strong>must not</strong> be released before any {@link ReferenceCountedOpenSslEngine}
-- * which depends upon the instance of this class is released. Otherwise if any method of
-- * {@link ReferenceCountedOpenSslEngine} is called which uses this class's JNI resources the JVM may crash.
-- */
--public final class ReferenceCountedOpenSslServerContext extends ReferenceCountedOpenSslContext {
-- private static final InternalLogger logger =
-- InternalLoggerFactory.getInstance(ReferenceCountedOpenSslServerContext.class);
-- private static final byte[] ID = {'n', 'e', 't', 't', 'y'};
-- private final OpenSslServerSessionContext sessionContext;
-- private final OpenSslKeyMaterialManager keyMaterialManager;
+- /**
+- * It is assumed this method is called in a synchronized block (or the constructor)!
+- */
+- private void calculateMaxWrapOverhead() {
+- maxWrapOverhead = SSL.getMaxWrapOverhead(ssl);
-
-- ReferenceCountedOpenSslServerContext(
-- X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory,
-- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory,
-- Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
-- long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[] protocols, boolean startTls,
-- boolean enableOcsp) throws SSLException {
-- this(trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory, ciphers,
-- cipherFilter, toNegotiator(apn), sessionCacheSize, sessionTimeout, clientAuth, protocols, startTls,
-- enableOcsp);
+- // maxWrapBufferSize must be set after maxWrapOverhead because there is a dependency on this value.
+- // If jdkCompatibility mode is off we allow enough space to encrypt 16 buffers at a time. This could be
+- // configurable in the future if necessary.
+- maxWrapBufferSize = jdkCompatibilityMode ? maxEncryptedPacketLength0() : maxEncryptedPacketLength0() << 4;
- }
-
-- private ReferenceCountedOpenSslServerContext(
-- X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory,
-- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory,
-- Iterable<String> ciphers, CipherSuiteFilter cipherFilter, OpenSslApplicationProtocolNegotiator apn,
-- long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[] protocols, boolean startTls,
-- boolean enableOcsp) throws SSLException {
-- super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, SSL.SSL_MODE_SERVER, keyCertChain,
-- clientAuth, protocols, startTls, enableOcsp, true);
-- // Create a new SSL_CTX and configure it.
-- boolean success = false;
-- try {
-- ServerContext context = newSessionContext(this, ctx, engineMap, trustCertCollection, trustManagerFactory,
-- keyCertChain, key, keyPassword, keyManagerFactory);
-- sessionContext = context.sessionContext;
-- keyMaterialManager = context.keyMaterialManager;
-- success = true;
-- } finally {
-- if (!success) {
-- release();
-- }
-- }
+- private int sslPending0() {
+- // OpenSSL has a limitation where if you call SSL_pending before the handshake is complete OpenSSL will throw a
+- // "called a function you should not call" error. Using the TLS_method instead of SSLv23_method may solve this
+- // issue but this API is only available in 1.1.0+ [1].
+- // [1] https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_new.html
+- return handshakeState != HandshakeState.FINISHED ? 0 : SSL.sslPending(ssl);
- }
-
-- @Override
-- public OpenSslServerSessionContext sessionContext() {
-- return sessionContext;
+- private boolean isBytesAvailableEnoughForWrap(int bytesAvailable, int plaintextLength, int numComponents) {
+- return bytesAvailable - (long) maxWrapOverhead * numComponents >= plaintextLength;
- }
-
- @Override
-- OpenSslKeyMaterialManager keyMaterialManager() {
-- return keyMaterialManager;
-- }
+- public final SSLEngineResult wrap(
+- final ByteBuffer[] srcs, int offset, final int length, final ByteBuffer dst) throws SSLException {
+- // Throw required runtime exceptions
+- if (srcs == null) {
+- throw new IllegalArgumentException("srcs is null");
+- }
+- if (dst == null) {
+- throw new IllegalArgumentException("dst is null");
+- }
-
-- static final class ServerContext {
-- OpenSslServerSessionContext sessionContext;
-- OpenSslKeyMaterialManager keyMaterialManager;
-- }
+- if (offset >= srcs.length || offset + length > srcs.length) {
+- throw new IndexOutOfBoundsException(
+- "offset: " + offset + ", length: " + length +
+- " (expected: offset <= offset + length <= srcs.length (" + srcs.length + "))");
+- }
-
-- static ServerContext newSessionContext(ReferenceCountedOpenSslContext thiz, long ctx, OpenSslEngineMap engineMap,
-- X509Certificate[] trustCertCollection,
-- TrustManagerFactory trustManagerFactory,
-- X509Certificate[] keyCertChain, PrivateKey key,
-- String keyPassword, KeyManagerFactory keyManagerFactory)
-- throws SSLException {
-- ServerContext result = new ServerContext();
-- try {
-- SSLContext.setVerify(ctx, SSL.SSL_CVERIFY_NONE, VERIFY_DEPTH);
-- if (!OpenSsl.useKeyManagerFactory()) {
-- if (keyManagerFactory != null) {
-- throw new IllegalArgumentException(
-- "KeyManagerFactory not supported");
+- if (dst.isReadOnly()) {
+- throw new ReadOnlyBufferException();
+- }
+-
+- synchronized (this) {
+- if (isOutboundDone()) {
+- // All drained in the outbound buffer
+- return isInboundDone() || isDestroyed() ? CLOSED_NOT_HANDSHAKING : NEED_UNWRAP_CLOSED;
+- }
+-
+- int bytesProduced = 0;
+- ByteBuf bioReadCopyBuf = null;
+- try {
+- // Setup the BIO buffer so that we directly write the encryption results into dst.
+- if (dst.isDirect()) {
+- SSL.bioSetByteBuffer(networkBIO, bufferAddress(dst) + dst.position(), dst.remaining(),
+- true);
+- } else {
+- bioReadCopyBuf = alloc.directBuffer(dst.remaining());
+- SSL.bioSetByteBuffer(networkBIO, memoryAddress(bioReadCopyBuf), bioReadCopyBuf.writableBytes(),
+- true);
+- }
+-
+- int bioLengthBefore = SSL.bioLengthByteBuffer(networkBIO);
+-
+- // Explicitly use outboundClosed as we want to drain any bytes that are still present.
+- if (outboundClosed) {
+- // If the outbound was closed we want to ensure we can produce the alert to the destination buffer.
+- // This is true even if we not using jdkCompatibilityMode.
+- //
+- // We use a plaintextLength of 2 as we at least want to have an alert fit into it.
+- // https://tools.ietf.org/html/rfc5246#section-7.2
+- if (!isBytesAvailableEnoughForWrap(dst.remaining(), 2, 1)) {
+- return new SSLEngineResult(BUFFER_OVERFLOW, getHandshakeStatus(), 0, 0);
+- }
+-
+- // There is something left to drain.
+- // See https://github.com/netty/netty/issues/6260
+- bytesProduced = SSL.bioFlushByteBuffer(networkBIO);
+- if (bytesProduced <= 0) {
+- return newResultMayFinishHandshake(NOT_HANDSHAKING, 0, 0);
+- }
+- // It is possible when the outbound was closed there was not enough room in the non-application
+- // buffers to hold the close_notify. We should keep trying to close until we consume all the data
+- // OpenSSL can give us.
+- if (!doSSLShutdown()) {
+- return newResultMayFinishHandshake(NOT_HANDSHAKING, 0, bytesProduced);
+- }
+- bytesProduced = bioLengthBefore - SSL.bioLengthByteBuffer(networkBIO);
+- return newResultMayFinishHandshake(NEED_WRAP, 0, bytesProduced);
- }
-- checkNotNull(keyCertChain, "keyCertChain");
-
-- setKeyMaterial(ctx, keyCertChain, key, keyPassword);
-- } else {
-- // javadocs state that keyManagerFactory has precedent over keyCertChain, and we must have a
-- // keyManagerFactory for the server so build one if it is not specified.
-- if (keyManagerFactory == null) {
-- keyManagerFactory = buildKeyManagerFactory(
-- keyCertChain, key, keyPassword, keyManagerFactory);
-- }
-- X509KeyManager keyManager = chooseX509KeyManager(keyManagerFactory.getKeyManagers());
-- result.keyMaterialManager = useExtendedKeyManager(keyManager) ?
-- new OpenSslExtendedKeyMaterialManager(
-- (X509ExtendedKeyManager) keyManager, keyPassword) :
-- new OpenSslKeyMaterialManager(keyManager, keyPassword);
-- }
-- } catch (Exception e) {
-- throw new SSLException("failed to set certificate and key", e);
-- }
-- try {
-- if (trustCertCollection != null) {
-- trustManagerFactory = buildTrustManagerFactory(trustCertCollection, trustManagerFactory);
-- } else if (trustManagerFactory == null) {
-- // Mimic the way SSLContext.getInstance(KeyManager[], null, null) works
-- trustManagerFactory = TrustManagerFactory.getInstance(
-- TrustManagerFactory.getDefaultAlgorithm());
-- trustManagerFactory.init((KeyStore) null);
-- }
+- // Flush any data that may be implicitly generated by OpenSSL (handshake, close, etc..).
+- SSLEngineResult.HandshakeStatus status = NOT_HANDSHAKING;
+- // Prepare OpenSSL to work in server mode and receive handshake
+- if (handshakeState != HandshakeState.FINISHED) {
+- if (handshakeState != HandshakeState.STARTED_EXPLICITLY) {
+- // Update accepted so we know we triggered the handshake via wrap
+- handshakeState = HandshakeState.STARTED_IMPLICITLY;
+- }
+-
+- // Flush any data that may have been written implicitly during the handshake by OpenSSL.
+- bytesProduced = SSL.bioFlushByteBuffer(networkBIO);
+-
+- if (pendingException != null) {
+- // TODO(scott): It is possible that when the handshake failed there was not enough room in the
+- // non-application buffers to hold the alert. We should get all the data before progressing on.
+- // However I'm not aware of a way to do this with the OpenSSL APIs.
+- // See https://github.com/netty/netty/issues/6385.
+-
+- // We produced / consumed some data during the handshake, signal back to the caller.
+- // If there is a handshake exception and we have produced data, we should send the data before
+- // we allow handshake() to throw the handshake exception.
+- //
+- // When the user calls wrap() again we will propagate the handshake error back to the user as
+- // soon as there is no more data to was produced (as part of an alert etc).
+- if (bytesProduced > 0) {
+- return newResult(NEED_WRAP, 0, bytesProduced);
+- }
+- // Nothing was produced see if there is a handshakeException that needs to be propagated
+- // to the caller by calling handshakeException() which will return the right HandshakeStatus
+- // if it can "recover" from the exception for now.
+- return newResult(handshakeException(), 0, 0);
+- }
+-
+- status = handshake();
+-
+- // Handshake may have generated more data, for example if the internal SSL buffer is small
+- // we may have freed up space by flushing above.
+- bytesProduced = bioLengthBefore - SSL.bioLengthByteBuffer(networkBIO);
+-
+- if (status == NEED_TASK) {
+- return newResult(status, 0, bytesProduced);
+- }
+-
+- if (bytesProduced > 0) {
+- // If we have filled up the dst buffer and we have not finished the handshake we should try to
+- // wrap again. Otherwise we should only try to wrap again if there is still data pending in
+- // SSL buffers.
+- return newResult(mayFinishHandshake(status != FINISHED ?
+- bytesProduced == bioLengthBefore ? NEED_WRAP :
+- getHandshakeStatus(SSL.bioLengthNonApplication(networkBIO)) : FINISHED),
+- 0, bytesProduced);
+- }
+-
+- if (status == NEED_UNWRAP) {
+- // Signal if the outbound is done or not.
+- return isOutboundDone() ? NEED_UNWRAP_CLOSED : NEED_UNWRAP_OK;
+- }
-
-- final X509TrustManager manager = chooseTrustManager(trustManagerFactory.getTrustManagers());
+- // Explicit use outboundClosed and not outboundClosed() as we want to drain any bytes that are
+- // still present.
+- if (outboundClosed) {
+- bytesProduced = SSL.bioFlushByteBuffer(networkBIO);
+- return newResultMayFinishHandshake(status, 0, bytesProduced);
+- }
+- }
-
-- // IMPORTANT: The callbacks set for verification must be static to prevent memory leak as
-- // otherwise the context can never be collected. This is because the JNI code holds
-- // a global reference to the callbacks.
-- //
-- // See https://github.com/netty/netty/issues/5372
+- final int endOffset = offset + length;
+- if (jdkCompatibilityMode) {
+- int srcsLen = 0;
+- for (int i = offset; i < endOffset; ++i) {
+- final ByteBuffer src = srcs[i];
+- if (src == null) {
+- throw new IllegalArgumentException("srcs[" + i + "] is null");
+- }
+- if (srcsLen == MAX_PLAINTEXT_LENGTH) {
+- continue;
+- }
-
-- // Use this to prevent an error when running on java < 7
-- if (useExtendedTrustManager(manager)) {
-- SSLContext.setCertVerifyCallback(ctx,
-- new ExtendedTrustManagerVerifyCallback(engineMap, (X509ExtendedTrustManager) manager));
-- } else {
-- SSLContext.setCertVerifyCallback(ctx, new TrustManagerVerifyCallback(engineMap, manager));
-- }
+- srcsLen += src.remaining();
+- if (srcsLen > MAX_PLAINTEXT_LENGTH || srcsLen < 0) {
+- // If srcLen > MAX_PLAINTEXT_LENGTH or secLen < 0 just set it to MAX_PLAINTEXT_LENGTH.
+- // This also help us to guard against overflow.
+- // We not break out here as we still need to check for null entries in srcs[].
+- srcsLen = MAX_PLAINTEXT_LENGTH;
+- }
+- }
-
-- X509Certificate[] issuers = manager.getAcceptedIssuers();
-- if (issuers != null && issuers.length > 0) {
-- long bio = 0;
-- try {
-- bio = toBIO(issuers);
-- if (!SSLContext.setCACertificateBio(ctx, bio)) {
-- throw new SSLException("unable to setup accepted issuers for trustmanager " + manager);
+- // jdkCompatibilityMode will only produce a single TLS packet, and we don't aggregate src buffers,
+- // so we always fix the number of buffers to 1 when checking if the dst buffer is large enough.
+- if (!isBytesAvailableEnoughForWrap(dst.remaining(), srcsLen, 1)) {
+- return new SSLEngineResult(BUFFER_OVERFLOW, getHandshakeStatus(), 0, 0);
- }
-- } finally {
-- freeBio(bio);
- }
-- }
-
-- if (PlatformDependent.javaVersion() >= 8) {
-- // Only do on Java8+ as SNIMatcher is not supported in earlier releases.
-- // IMPORTANT: The callbacks set for hostname matching must be static to prevent memory leak as
-- // otherwise the context can never be collected. This is because the JNI code holds
-- // a global reference to the matcher.
-- SSLContext.setSniHostnameMatcher(ctx, new OpenSslSniHostnameMatcher(engineMap));
-- }
-- } catch (SSLException e) {
-- throw e;
-- } catch (Exception e) {
-- throw new SSLException("unable to setup trustmanager", e);
-- }
+- // There was no pending data in the network BIO -- encrypt any application data
+- int bytesConsumed = 0;
+- assert bytesProduced == 0;
-
-- result.sessionContext = new OpenSslServerSessionContext(thiz);
-- result.sessionContext.setSessionIdContext(ID);
-- return result;
-- }
+- // Flush any data that may have been written implicitly by OpenSSL in case a shutdown/alert occurs.
+- bytesProduced = SSL.bioFlushByteBuffer(networkBIO);
-
-- private static final class TrustManagerVerifyCallback extends AbstractCertificateVerifier {
-- private final X509TrustManager manager;
+- if (bytesProduced > 0) {
+- return newResultMayFinishHandshake(status, bytesConsumed, bytesProduced);
+- }
+- // There was a pending exception that we just delayed because there was something to produce left.
+- // Throw it now and shutdown the engine.
+- if (pendingException != null) {
+- Throwable error = pendingException;
+- pendingException = null;
+- shutdown();
+- // Throw a new exception wrapping the pending exception, so the stacktrace is meaningful and
+- // contains all the details.
+- throw new SSLException(error);
+- }
-
-- TrustManagerVerifyCallback(OpenSslEngineMap engineMap, X509TrustManager manager) {
-- super(engineMap);
-- this.manager = manager;
-- }
+- for (; offset < endOffset; ++offset) {
+- final ByteBuffer src = srcs[offset];
+- final int remaining = src.remaining();
+- if (remaining == 0) {
+- continue;
+- }
-
-- @Override
-- void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts, String auth)
-- throws Exception {
-- manager.checkClientTrusted(peerCerts, auth);
-- }
-- }
+- final int bytesWritten;
+- if (jdkCompatibilityMode) {
+- // Write plaintext application data to the SSL engine. We don't have to worry about checking
+- // if there is enough space if jdkCompatibilityMode because we only wrap at most
+- // MAX_PLAINTEXT_LENGTH and we loop over the input before hand and check if there is space.
+- bytesWritten = writePlaintextData(src, min(remaining, MAX_PLAINTEXT_LENGTH - bytesConsumed));
+- } else {
+- // OpenSSL's SSL_write keeps state between calls. We should make sure the amount we attempt to
+- // write is guaranteed to succeed so we don't have to worry about keeping state consistent
+- // between calls.
+- final int availableCapacityForWrap = dst.remaining() - bytesProduced - maxWrapOverhead;
+- if (availableCapacityForWrap <= 0) {
+- return new SSLEngineResult(BUFFER_OVERFLOW, getHandshakeStatus(), bytesConsumed,
+- bytesProduced);
+- }
+- bytesWritten = writePlaintextData(src, min(remaining, availableCapacityForWrap));
+- }
-
-- private static final class ExtendedTrustManagerVerifyCallback extends AbstractCertificateVerifier {
-- private final X509ExtendedTrustManager manager;
+- // Determine how much encrypted data was generated.
+- //
+- // Even if SSL_write doesn't consume any application data it is possible that OpenSSL will
+- // produce non-application data into the BIO. For example session tickets....
+- // See https://github.com/netty/netty/issues/10041
+- final int pendingNow = SSL.bioLengthByteBuffer(networkBIO);
+- bytesProduced += bioLengthBefore - pendingNow;
+- bioLengthBefore = pendingNow;
-
-- ExtendedTrustManagerVerifyCallback(OpenSslEngineMap engineMap, X509ExtendedTrustManager manager) {
-- super(engineMap);
-- this.manager = manager;
-- }
+- if (bytesWritten > 0) {
+- bytesConsumed += bytesWritten;
-
-- @Override
-- void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts, String auth)
-- throws Exception {
-- manager.checkClientTrusted(peerCerts, auth, engine);
-- }
-- }
+- if (jdkCompatibilityMode || bytesProduced == dst.remaining()) {
+- return newResultMayFinishHandshake(status, bytesConsumed, bytesProduced);
+- }
+- } else {
+- int sslError = SSL.getError(ssl, bytesWritten);
+- if (sslError == SSL.SSL_ERROR_ZERO_RETURN) {
+- // This means the connection was shutdown correctly, close inbound and outbound
+- if (!receivedShutdown) {
+- closeAll();
-
-- private static final class OpenSslSniHostnameMatcher implements SniHostNameMatcher {
-- private final OpenSslEngineMap engineMap;
+- bytesProduced += bioLengthBefore - SSL.bioLengthByteBuffer(networkBIO);
-
-- OpenSslSniHostnameMatcher(OpenSslEngineMap engineMap) {
-- this.engineMap = engineMap;
-- }
+- // If we have filled up the dst buffer and we have not finished the handshake we should
+- // try to wrap again. Otherwise we should only try to wrap again if there is still data
+- // pending in SSL buffers.
+- SSLEngineResult.HandshakeStatus hs = mayFinishHandshake(
+- status != FINISHED ? bytesProduced == dst.remaining() ? NEED_WRAP
+- : getHandshakeStatus(SSL.bioLengthNonApplication(networkBIO))
+- : FINISHED);
+- return newResult(hs, bytesConsumed, bytesProduced);
+- }
-
-- @Override
-- public boolean match(long ssl, String hostname) {
-- ReferenceCountedOpenSslEngine engine = engineMap.get(ssl);
-- if (engine != null) {
-- return engine.checkSniHostnameMatch(hostname);
-- }
-- logger.warn("No ReferenceCountedOpenSslEngine found for SSL pointer: {}", ssl);
-- return false;
-- }
-- }
--}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/SslContext.java b/handler/src/main/java/io/netty/handler/ssl/SslContext.java
-index 4998d0d..8dbc3cf 100644
---- a/handler/src/main/java/io/netty/handler/ssl/SslContext.java
-+++ b/handler/src/main/java/io/netty/handler/ssl/SslContext.java
-@@ -115,11 +115,7 @@ public abstract class SslContext {
- }
-
- private static SslProvider defaultProvider() {
-- if (OpenSsl.isAvailable()) {
-- return SslProvider.OPENSSL;
-- } else {
-- return SslProvider.JDK;
-- }
-+ return SslProvider.JDK;
- }
-
- /**
-@@ -416,18 +412,6 @@ public abstract class SslContext {
- trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword,
- keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout,
- clientAuth, protocols, startTls);
-- case OPENSSL:
-- verifyNullSslContextProvider(provider, sslContextProvider);
-- return new OpenSslServerContext(
-- trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword,
-- keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout,
-- clientAuth, protocols, startTls, enableOcsp);
-- case OPENSSL_REFCNT:
-- verifyNullSslContextProvider(provider, sslContextProvider);
-- return new ReferenceCountedOpenSslServerContext(
-- trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword,
-- keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout,
-- clientAuth, protocols, startTls, enableOcsp);
- default:
- throw new Error(provider.toString());
- }
-@@ -770,18 +754,6 @@ public abstract class SslContext {
- return new JdkSslClientContext(sslContextProvider,
- trustCert, trustManagerFactory, keyCertChain, key, keyPassword,
- keyManagerFactory, ciphers, cipherFilter, apn, protocols, sessionCacheSize, sessionTimeout);
-- case OPENSSL:
-- verifyNullSslContextProvider(provider, sslContextProvider);
-- return new OpenSslClientContext(
-- trustCert, trustManagerFactory, keyCertChain, key, keyPassword,
-- keyManagerFactory, ciphers, cipherFilter, apn, protocols, sessionCacheSize, sessionTimeout,
-- enableOcsp);
-- case OPENSSL_REFCNT:
-- verifyNullSslContextProvider(provider, sslContextProvider);
-- return new ReferenceCountedOpenSslClientContext(
-- trustCert, trustManagerFactory, keyCertChain, key, keyPassword,
-- keyManagerFactory, ciphers, cipherFilter, apn, protocols, sessionCacheSize, sessionTimeout,
-- enableOcsp);
- default:
- throw new Error(provider.toString());
- }
-diff --git a/handler/src/main/java/io/netty/handler/ssl/SslHandler.java b/handler/src/main/java/io/netty/handler/ssl/SslHandler.java
-index c054964..05c451a 100644
---- a/handler/src/main/java/io/netty/handler/ssl/SslHandler.java
-+++ b/handler/src/main/java/io/netty/handler/ssl/SslHandler.java
-@@ -159,6 +159,12 @@ import static io.netty.handler.ssl.SslUtils.getEncryptedPacketLength;
- * <a href="https://github.com/netty/netty/issues/832">#832</a> in our issue tracker.
- */
- public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundHandler {
-+ private static final int MAX_PLAINTEXT_LENGTH = 16 * 1024; // 2^14
-+ private static final int MAX_COMPRESSED_LENGTH = MAX_PLAINTEXT_LENGTH + 1024;
-+ private static final int MAX_CIPHERTEXT_LENGTH = MAX_COMPRESSED_LENGTH + 1024;
-+ // Header (5) + Data (2^14) + Compression (1024) + Encryption (1024) + MAC (20) + Padding (256)
-+ static final int MAX_ENCRYPTED_PACKET_LENGTH = MAX_CIPHERTEXT_LENGTH + 5 + 20 + 256;
-+ static final int MAX_ENCRYPTION_OVERHEAD_LENGTH = MAX_ENCRYPTED_PACKET_LENGTH - MAX_PLAINTEXT_LENGTH;
-
- private static final InternalLogger logger =
- InternalLoggerFactory.getInstance(SslHandler.class);
-@@ -181,40 +187,6 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
- new ClosedChannelException(), SslHandler.class, "channelInactive(...)");
-
- private enum SslEngineType {
-- TCNATIVE(true, COMPOSITE_CUMULATOR) {
-- @Override
-- SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int len, ByteBuf out)
-- throws SSLException {
-- int nioBufferCount = in.nioBufferCount();
-- int writerIndex = out.writerIndex();
-- final SSLEngineResult result;
-- if (nioBufferCount > 1) {
-- /*
-- * If {@link OpenSslEngine} is in use,
-- * we can use a special {@link OpenSslEngine#unwrap(ByteBuffer[], ByteBuffer[])} method
-- * that accepts multiple {@link ByteBuffer}s without additional memory copies.
-- */
-- ReferenceCountedOpenSslEngine opensslEngine = (ReferenceCountedOpenSslEngine) handler.engine;
-- try {
-- handler.singleBuffer[0] = toByteBuffer(out, writerIndex,
-- out.writableBytes());
-- result = opensslEngine.unwrap(in.nioBuffers(readerIndex, len), handler.singleBuffer);
-- } finally {
-- handler.singleBuffer[0] = null;
+- return newResult(NOT_HANDSHAKING, bytesConsumed, bytesProduced);
+- } else if (sslError == SSL.SSL_ERROR_WANT_READ) {
+- // If there is no pending data to read from BIO we should go back to event loop and try
+- // to read more data [1]. It is also possible that event loop will detect the socket has
+- // been closed. [1] https://www.openssl.org/docs/manmaster/ssl/SSL_write.html
+- return newResult(NEED_UNWRAP, bytesConsumed, bytesProduced);
+- } else if (sslError == SSL.SSL_ERROR_WANT_WRITE) {
+- // SSL_ERROR_WANT_WRITE typically means that the underlying transport is not writable
+- // and we should set the "want write" flag on the selector and try again when the
+- // underlying transport is writable [1]. However we are not directly writing to the
+- // underlying transport and instead writing to a BIO buffer. The OpenSsl documentation
+- // says we should do the following [1]:
+- //
+- // "When using a buffering BIO, like a BIO pair, data must be written into or retrieved
+- // out of the BIO before being able to continue."
+- //
+- // In practice this means the destination buffer doesn't have enough space for OpenSSL
+- // to write encrypted data to. This is an OVERFLOW condition.
+- // [1] https://www.openssl.org/docs/manmaster/ssl/SSL_write.html
+- if (bytesProduced > 0) {
+- // If we produced something we should report this back and let the user call
+- // wrap again.
+- return newResult(NEED_WRAP, bytesConsumed, bytesProduced);
+- }
+- return newResult(BUFFER_OVERFLOW, status, bytesConsumed, bytesProduced);
+- } else if (sslError == SSL.SSL_ERROR_WANT_X509_LOOKUP ||
+- sslError == SSL.SSL_ERROR_WANT_CERTIFICATE_VERIFY ||
+- sslError == SSL.SSL_ERROR_WANT_PRIVATE_KEY_OPERATION) {
+-
+- return newResult(NEED_TASK, bytesConsumed, bytesProduced);
+- } else {
+- // Everything else is considered as error
+- throw shutdownWithError("SSL_write", sslError);
+- }
- }
-- } else {
-- result = handler.engine.unwrap(toByteBuffer(in, readerIndex, len),
-- toByteBuffer(out, writerIndex, out.writableBytes()));
- }
-- out.writerIndex(writerIndex + result.bytesProduced());
-- return result;
-- }
--
-- @Override
-- int calculateWrapBufferCapacity(SslHandler handler, int pendingBytes, int numComponents) {
-- return ReferenceCountedOpenSslEngine.calculateOutNetBufSize(pendingBytes, numComponents);
-- }
-- },
- CONSCRYPT(true, COMPOSITE_CUMULATOR) {
- @Override
- SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int len, ByteBuf out)
-@@ -265,9 +237,6 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
- };
-
- static SslEngineType forEngine(SSLEngine engine) {
-- if (engine instanceof ReferenceCountedOpenSslEngine) {
-- return TCNATIVE;
-- }
- if (engine instanceof ConscryptAlpnSslEngine) {
- return CONSCRYPT;
- }
-@@ -1034,7 +1003,7 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
-
- boolean nonSslRecord = false;
-
-- while (totalLength < ReferenceCountedOpenSslEngine.MAX_ENCRYPTED_PACKET_LENGTH) {
-+ while (totalLength < MAX_ENCRYPTED_PACKET_LENGTH) {
- final int readableBytes = endOffset - offset;
- if (readableBytes < SslUtils.SSL_RECORD_HEADER_LENGTH) {
- break;
-@@ -1055,7 +1024,7 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
- }
-
- int newTotalLength = totalLength + packetLength;
-- if (newTotalLength > ReferenceCountedOpenSslEngine.MAX_ENCRYPTED_PACKET_LENGTH) {
-+ if (newTotalLength > MAX_ENCRYPTED_PACKET_LENGTH) {
- // Don't read too much.
- break;
- }
-diff --git a/handler/src/main/java/io/netty/handler/ssl/ocsp/OcspClientHandler.java b/handler/src/main/java/io/netty/handler/ssl/ocsp/OcspClientHandler.java
-deleted file mode 100644
-index aff0949..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/ocsp/OcspClientHandler.java
-+++ /dev/null
-@@ -1,65 +0,0 @@
--/*
-- * Copyright 2017 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl.ocsp;
--
--import io.netty.channel.ChannelHandlerContext;
--import io.netty.channel.ChannelInboundHandlerAdapter;
--import io.netty.handler.ssl.ReferenceCountedOpenSslContext;
--import io.netty.handler.ssl.ReferenceCountedOpenSslEngine;
--import io.netty.handler.ssl.SslHandshakeCompletionEvent;
--import io.netty.util.internal.ObjectUtil;
--import io.netty.util.internal.ThrowableUtil;
--import io.netty.util.internal.UnstableApi;
+- return newResultMayFinishHandshake(status, bytesConsumed, bytesProduced);
+- } finally {
+- SSL.bioClearByteBuffer(networkBIO);
+- if (bioReadCopyBuf == null) {
+- dst.position(dst.position() + bytesProduced);
+- } else {
+- assert bioReadCopyBuf.readableBytes() <= dst.remaining() : "The destination buffer " + dst +
+- " didn't have enough remaining space to hold the encrypted content in " + bioReadCopyBuf;
+- dst.put(bioReadCopyBuf.internalNioBuffer(bioReadCopyBuf.readerIndex(), bytesProduced));
+- bioReadCopyBuf.release();
+- }
+- }
+- }
+- }
-
--import javax.net.ssl.SSLHandshakeException;
+- private SSLEngineResult newResult(SSLEngineResult.HandshakeStatus hs, int bytesConsumed, int bytesProduced) {
+- return newResult(OK, hs, bytesConsumed, bytesProduced);
+- }
-
--/**
-- * A handler for SSL clients to handle and act upon stapled OCSP responses.
-- *
-- * @see ReferenceCountedOpenSslContext#enableOcsp()
-- * @see ReferenceCountedOpenSslEngine#getOcspResponse()
-- */
--@UnstableApi
--public abstract class OcspClientHandler extends ChannelInboundHandlerAdapter {
+- private SSLEngineResult newResult(SSLEngineResult.Status status, SSLEngineResult.HandshakeStatus hs,
+- int bytesConsumed, int bytesProduced) {
+- // If isOutboundDone, then the data from the network BIO
+- // was the close_notify message and all was consumed we are not required to wait
+- // for the receipt the peer's close_notify message -- shutdown.
+- if (isOutboundDone()) {
+- if (isInboundDone()) {
+- // If the inbound was done as well, we need to ensure we return NOT_HANDSHAKING to signal we are done.
+- hs = NOT_HANDSHAKING;
-
-- private static final SSLHandshakeException OCSP_VERIFICATION_EXCEPTION = ThrowableUtil.unknownStackTrace(
-- new SSLHandshakeException("Bad OCSP response"), OcspClientHandler.class, "verify(...)");
+- // As the inbound and the outbound is done we can shutdown the engine now.
+- shutdown();
+- }
+- return new SSLEngineResult(CLOSED, hs, bytesConsumed, bytesProduced);
+- }
+- if (hs == NEED_TASK) {
+- // Set needTask to true so getHandshakeStatus() will return the correct value.
+- needTask = true;
+- }
+- return new SSLEngineResult(status, hs, bytesConsumed, bytesProduced);
+- }
-
-- private final ReferenceCountedOpenSslEngine engine;
+- private SSLEngineResult newResultMayFinishHandshake(SSLEngineResult.HandshakeStatus hs,
+- int bytesConsumed, int bytesProduced) throws SSLException {
+- return newResult(mayFinishHandshake(hs != FINISHED ? getHandshakeStatus() : FINISHED),
+- bytesConsumed, bytesProduced);
+- }
-
-- protected OcspClientHandler(ReferenceCountedOpenSslEngine engine) {
-- this.engine = ObjectUtil.checkNotNull(engine, "engine");
+- private SSLEngineResult newResultMayFinishHandshake(SSLEngineResult.Status status,
+- SSLEngineResult.HandshakeStatus hs,
+- int bytesConsumed, int bytesProduced) throws SSLException {
+- return newResult(status, mayFinishHandshake(hs != FINISHED ? getHandshakeStatus() : FINISHED),
+- bytesConsumed, bytesProduced);
- }
-
- /**
-- * @see ReferenceCountedOpenSslEngine#getOcspResponse()
+- * Log the error, shutdown the engine and throw an exception.
- */
-- protected abstract boolean verify(ChannelHandlerContext ctx, ReferenceCountedOpenSslEngine engine) throws Exception;
+- private SSLException shutdownWithError(String operations, int sslError) {
+- return shutdownWithError(operations, sslError, SSL.getLastErrorNumber());
+- }
-
-- @Override
-- public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
-- if (evt instanceof SslHandshakeCompletionEvent) {
-- ctx.pipeline().remove(this);
+- private SSLException shutdownWithError(String operation, int sslError, int error) {
+- String errorString = SSL.getErrorString(error);
+- if (logger.isDebugEnabled()) {
+- logger.debug("{} failed with {}: OpenSSL error: {} {}",
+- operation, sslError, error, errorString);
+- }
-
-- SslHandshakeCompletionEvent event = (SslHandshakeCompletionEvent) evt;
-- if (event.isSuccess() && !verify(ctx, engine)) {
-- throw OCSP_VERIFICATION_EXCEPTION;
-- }
+- // There was an internal error -- shutdown
+- shutdown();
+- if (handshakeState == HandshakeState.FINISHED) {
+- return new SSLException(errorString);
- }
-
-- ctx.fireUserEventTriggered(evt);
+- SSLHandshakeException exception = new SSLHandshakeException(errorString);
+- // If we have a handshakeException stored already we should include it as well to help the user debug things.
+- if (pendingException != null) {
+- exception.initCause(pendingException);
+- pendingException = null;
+- }
+- return exception;
- }
--}
-diff --git a/handler/src/main/java/io/netty/handler/ssl/ocsp/package-info.java b/handler/src/main/java/io/netty/handler/ssl/ocsp/package-info.java
-deleted file mode 100644
-index 2883ff4..0000000
---- a/handler/src/main/java/io/netty/handler/ssl/ocsp/package-info.java
-+++ /dev/null
-@@ -1,23 +0,0 @@
--/*
-- * Copyright 2017 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
-
--/**
-- * <a href="https://en.wikipedia.org/wiki/OCSP_stapling">OCSP stapling</a>,
-- * formally known as the TLS Certificate Status Request extension, is an
-- * alternative approach to the Online Certificate Status Protocol (OCSP)
-- * for checking the revocation status of X.509 digital certificates.
-- */
--package io.netty.handler.ssl.ocsp;
-diff --git a/handler/src/test/java/io/netty/handler/ssl/JdkOpenSslEngineInteroptTest.java b/handler/src/test/java/io/netty/handler/ssl/JdkOpenSslEngineInteroptTest.java
-deleted file mode 100644
-index d696d6b..0000000
---- a/handler/src/test/java/io/netty/handler/ssl/JdkOpenSslEngineInteroptTest.java
-+++ /dev/null
-@@ -1,108 +0,0 @@
--/*
-- * Copyright 2016 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
+- public final SSLEngineResult unwrap(
+- final ByteBuffer[] srcs, int srcsOffset, final int srcsLength,
+- final ByteBuffer[] dsts, int dstsOffset, final int dstsLength) throws SSLException {
+-
+- // Throw required runtime exceptions
+- ObjectUtil.checkNotNull(srcs, "srcs");
+- if (srcsOffset >= srcs.length
+- || srcsOffset + srcsLength > srcs.length) {
+- throw new IndexOutOfBoundsException(
+- "offset: " + srcsOffset + ", length: " + srcsLength +
+- " (expected: offset <= offset + length <= srcs.length (" + srcs.length + "))");
+- }
+- if (dsts == null) {
+- throw new IllegalArgumentException("dsts is null");
+- }
+- if (dstsOffset >= dsts.length || dstsOffset + dstsLength > dsts.length) {
+- throw new IndexOutOfBoundsException(
+- "offset: " + dstsOffset + ", length: " + dstsLength +
+- " (expected: offset <= offset + length <= dsts.length (" + dsts.length + "))");
+- }
+- long capacity = 0;
+- final int dstsEndOffset = dstsOffset + dstsLength;
+- for (int i = dstsOffset; i < dstsEndOffset; i ++) {
+- ByteBuffer dst = dsts[i];
+- if (dst == null) {
+- throw new IllegalArgumentException("dsts[" + i + "] is null");
+- }
+- if (dst.isReadOnly()) {
+- throw new ReadOnlyBufferException();
+- }
+- capacity += dst.remaining();
+- }
-
--import org.junit.BeforeClass;
--import org.junit.Test;
--import org.junit.runner.RunWith;
--import org.junit.runners.Parameterized;
+- final int srcsEndOffset = srcsOffset + srcsLength;
+- long len = 0;
+- for (int i = srcsOffset; i < srcsEndOffset; i++) {
+- ByteBuffer src = srcs[i];
+- if (src == null) {
+- throw new IllegalArgumentException("srcs[" + i + "] is null");
+- }
+- len += src.remaining();
+- }
-
--import java.util.ArrayList;
--import java.util.Collection;
--import java.util.List;
+- synchronized (this) {
+- if (isInboundDone()) {
+- return isOutboundDone() || isDestroyed() ? CLOSED_NOT_HANDSHAKING : NEED_WRAP_CLOSED;
+- }
+-
+- SSLEngineResult.HandshakeStatus status = NOT_HANDSHAKING;
+- // Prepare OpenSSL to work in server mode and receive handshake
+- if (handshakeState != HandshakeState.FINISHED) {
+- if (handshakeState != HandshakeState.STARTED_EXPLICITLY) {
+- // Update accepted so we know we triggered the handshake via wrap
+- handshakeState = HandshakeState.STARTED_IMPLICITLY;
+- }
+-
+- status = handshake();
+-
+- if (status == NEED_TASK) {
+- return newResult(status, 0, 0);
+- }
+-
+- if (status == NEED_WRAP) {
+- return NEED_WRAP_OK;
+- }
+- // Check if the inbound is considered to be closed if so let us try to wrap again.
+- if (isInboundDone) {
+- return NEED_WRAP_CLOSED;
+- }
+- }
+-
+- int sslPending = sslPending0();
+- int packetLength;
+- // The JDK implies that only a single SSL packet should be processed per unwrap call [1]. If we are in
+- // JDK compatibility mode then we should honor this, but if not we just wrap as much as possible. If there
+- // are multiple records or partial records this may reduce thrashing events through the pipeline.
+- // [1] https://docs.oracle.com/javase/7/docs/api/javax/net/ssl/SSLEngine.html
+- if (jdkCompatibilityMode) {
+- if (len < SSL_RECORD_HEADER_LENGTH) {
+- return newResultMayFinishHandshake(BUFFER_UNDERFLOW, status, 0, 0);
+- }
+-
+- packetLength = SslUtils.getEncryptedPacketLength(srcs, srcsOffset);
+- if (packetLength == SslUtils.NOT_ENCRYPTED) {
+- throw new NotSslRecordException("not an SSL/TLS record");
+- }
+-
+- final int packetLengthDataOnly = packetLength - SSL_RECORD_HEADER_LENGTH;
+- if (packetLengthDataOnly > capacity) {
+- // Not enough space in the destination buffer so signal the caller that the buffer needs to be
+- // increased.
+- if (packetLengthDataOnly > MAX_RECORD_SIZE) {
+- // The packet length MUST NOT exceed 2^14 [1]. However we do accommodate more data to support
+- // legacy use cases which may violate this condition (e.g. OpenJDK's SslEngineImpl). If the max
+- // length is exceeded we fail fast here to avoid an infinite loop due to the fact that we
+- // won't allocate a buffer large enough.
+- // [1] https://tools.ietf.org/html/rfc5246#section-6.2.1
+- throw new SSLException("Illegal packet length: " + packetLengthDataOnly + " > " +
+- session.getApplicationBufferSize());
+- } else {
+- session.tryExpandApplicationBufferSize(packetLengthDataOnly);
+- }
+- return newResultMayFinishHandshake(BUFFER_OVERFLOW, status, 0, 0);
+- }
+-
+- if (len < packetLength) {
+- // We either don't have enough data to read the packet length or not enough for reading the whole
+- // packet.
+- return newResultMayFinishHandshake(BUFFER_UNDERFLOW, status, 0, 0);
+- }
+- } else if (len == 0 && sslPending <= 0) {
+- return newResultMayFinishHandshake(BUFFER_UNDERFLOW, status, 0, 0);
+- } else if (capacity == 0) {
+- return newResultMayFinishHandshake(BUFFER_OVERFLOW, status, 0, 0);
+- } else {
+- packetLength = (int) min(MAX_VALUE, len);
+- }
+-
+- // This must always be the case when we reached here as if not we returned BUFFER_UNDERFLOW.
+- assert srcsOffset < srcsEndOffset;
+-
+- // This must always be the case if we reached here.
+- assert capacity > 0;
+-
+- // Number of produced bytes
+- int bytesProduced = 0;
+- int bytesConsumed = 0;
+- try {
+- srcLoop:
+- for (;;) {
+- ByteBuffer src = srcs[srcsOffset];
+- int remaining = src.remaining();
+- final ByteBuf bioWriteCopyBuf;
+- int pendingEncryptedBytes;
+- if (remaining == 0) {
+- if (sslPending <= 0) {
+- // We must skip empty buffers as BIO_write will return 0 if asked to write something
+- // with length 0.
+- if (++srcsOffset >= srcsEndOffset) {
+- break;
+- }
+- continue;
+- } else {
+- bioWriteCopyBuf = null;
+- pendingEncryptedBytes = SSL.bioLengthByteBuffer(networkBIO);
+- }
+- } else {
+- // Write more encrypted data into the BIO. Ensure we only read one packet at a time as
+- // stated in the SSLEngine javadocs.
+- pendingEncryptedBytes = min(packetLength, remaining);
+- bioWriteCopyBuf = writeEncryptedData(src, pendingEncryptedBytes);
+- }
+- try {
+- for (;;) {
+- ByteBuffer dst = dsts[dstsOffset];
+- if (!dst.hasRemaining()) {
+- // No space left in the destination buffer, skip it.
+- if (++dstsOffset >= dstsEndOffset) {
+- break srcLoop;
+- }
+- continue;
+- }
+-
+- int bytesRead = readPlaintextData(dst);
+- // We are directly using the ByteBuffer memory for the write, and so we only know what has
+- // been consumed after we let SSL decrypt the data. At this point we should update the
+- // number of bytes consumed, update the ByteBuffer position, and release temp ByteBuf.
+- int localBytesConsumed = pendingEncryptedBytes - SSL.bioLengthByteBuffer(networkBIO);
+- bytesConsumed += localBytesConsumed;
+- packetLength -= localBytesConsumed;
+- pendingEncryptedBytes -= localBytesConsumed;
+- src.position(src.position() + localBytesConsumed);
+-
+- if (bytesRead > 0) {
+- bytesProduced += bytesRead;
+-
+- if (!dst.hasRemaining()) {
+- sslPending = sslPending0();
+- // Move to the next dst buffer as this one is full.
+- if (++dstsOffset >= dstsEndOffset) {
+- return sslPending > 0 ?
+- newResult(BUFFER_OVERFLOW, status, bytesConsumed, bytesProduced) :
+- newResultMayFinishHandshake(isInboundDone() ? CLOSED : OK, status,
+- bytesConsumed, bytesProduced);
+- }
+- } else if (packetLength == 0 || jdkCompatibilityMode) {
+- // We either consumed all data or we are in jdkCompatibilityMode and have consumed
+- // a single TLS packet and should stop consuming until this method is called again.
+- break srcLoop;
+- }
+- } else {
+- int sslError = SSL.getError(ssl, bytesRead);
+- if (sslError == SSL.SSL_ERROR_WANT_READ || sslError == SSL.SSL_ERROR_WANT_WRITE) {
+- // break to the outer loop as we want to read more data which means we need to
+- // write more to the BIO.
+- break;
+- } else if (sslError == SSL.SSL_ERROR_ZERO_RETURN) {
+- // This means the connection was shutdown correctly, close inbound and outbound
+- if (!receivedShutdown) {
+- closeAll();
+- }
+- return newResultMayFinishHandshake(isInboundDone() ? CLOSED : OK, status,
+- bytesConsumed, bytesProduced);
+- } else if (sslError == SSL.SSL_ERROR_WANT_X509_LOOKUP ||
+- sslError == SSL.SSL_ERROR_WANT_CERTIFICATE_VERIFY ||
+- sslError == SSL.SSL_ERROR_WANT_PRIVATE_KEY_OPERATION) {
+- return newResult(isInboundDone() ? CLOSED : OK,
+- NEED_TASK, bytesConsumed, bytesProduced);
+- } else {
+- return sslReadErrorResult(sslError, SSL.getLastErrorNumber(), bytesConsumed,
+- bytesProduced);
+- }
+- }
+- }
-
--import static io.netty.handler.ssl.OpenSslTestUtils.checkShouldUseKeyManagerFactory;
--import static io.netty.internal.tcnative.SSL.SSL_CVERIFY_IGNORED;
--import static org.junit.Assume.assumeTrue;
+- if (++srcsOffset >= srcsEndOffset) {
+- break;
+- }
+- } finally {
+- if (bioWriteCopyBuf != null) {
+- bioWriteCopyBuf.release();
+- }
+- }
+- }
+- } finally {
+- SSL.bioClearByteBuffer(networkBIO);
+- rejectRemoteInitiatedRenegotiation();
+- }
-
--(a)RunWith(Parameterized.class)
--public class JdkOpenSslEngineInteroptTest extends SSLEngineTest {
+- // Check to see if we received a close_notify message from the peer.
+- if (!receivedShutdown && (SSL.getShutdown(ssl) & SSL.SSL_RECEIVED_SHUTDOWN) == SSL.SSL_RECEIVED_SHUTDOWN) {
+- closeAll();
+- }
-
-- @Parameterized.Parameters(name = "{index}: bufferType = {0}")
-- public static Collection<Object> data() {
-- List<Object> params = new ArrayList<Object>();
-- for (BufferType type: BufferType.values()) {
-- params.add(type);
+- return newResultMayFinishHandshake(isInboundDone() ? CLOSED : OK, status, bytesConsumed, bytesProduced);
- }
-- return params;
- }
-
-- public JdkOpenSslEngineInteroptTest(BufferType type) {
-- super(type);
+- private SSLEngineResult sslReadErrorResult(int error, int stackError, int bytesConsumed, int bytesProduced)
+- throws SSLException {
+- // Check if we have a pending handshakeException and if so see if we need to consume all pending data from the
+- // BIO first or can just shutdown and throw it now.
+- // This is needed so we ensure close_notify etc is correctly send to the remote peer.
+- // See https://github.com/netty/netty/issues/3900
+- if (SSL.bioLengthNonApplication(networkBIO) > 0) {
+- // we seems to have data left that needs to be transferred and so the user needs
+- // call wrap(...). Store the error so we can pick it up later.
+- String message = SSL.getErrorString(stackError);
+- SSLException exception = handshakeState == HandshakeState.FINISHED ?
+- new SSLException(message) : new SSLHandshakeException(message);
+- if (pendingException == null) {
+- pendingException = exception;
+- } else {
+- ThrowableUtil.addSuppressed(pendingException, exception);
+- }
+- // We need to clear all errors so we not pick up anything that was left on the stack on the next
+- // operation. Note that shutdownWithError(...) will cleanup the stack as well so its only needed here.
+- SSL.clearError();
+- return new SSLEngineResult(OK, NEED_WRAP, bytesConsumed, bytesProduced);
+- }
+- throw shutdownWithError("SSL_read", error, stackError);
- }
-
-- @BeforeClass
-- public static void checkOpenSsl() {
-- assumeTrue(OpenSsl.isAvailable());
+- private void closeAll() throws SSLException {
+- receivedShutdown = true;
+- closeOutbound();
+- closeInbound();
- }
-
-- @Override
-- protected SslProvider sslClientProvider() {
-- return SslProvider.JDK;
+- private void rejectRemoteInitiatedRenegotiation() throws SSLHandshakeException {
+- // As rejectRemoteInitiatedRenegotiation() is called in a finally block we also need to check if we shutdown
+- // the engine before as otherwise SSL.getHandshakeCount(ssl) will throw an NPE if the passed in ssl is 0.
+- // See https://github.com/netty/netty/issues/7353
+- if (!isDestroyed() && SSL.getHandshakeCount(ssl) > 1 &&
+- // As we may count multiple handshakes when TLSv1.3 is used we should just ignore this here as
+- // renegotiation is not supported in TLSv1.3 as per spec.
+- !SslUtils.PROTOCOL_TLS_V1_3.equals(session.getProtocol()) && handshakeState == HandshakeState.FINISHED) {
+- // TODO: In future versions me may also want to send a fatal_alert to the client and so notify it
+- // that the renegotiation failed.
+- shutdown();
+- throw new SSLHandshakeException("remote-initiated renegotiation not allowed");
+- }
- }
-
-- @Override
-- protected SslProvider sslServerProvider() {
-- return SslProvider.OPENSSL;
+- public final SSLEngineResult unwrap(final ByteBuffer[] srcs, final ByteBuffer[] dsts) throws SSLException {
+- return unwrap(srcs, 0, srcs.length, dsts, 0, dsts.length);
- }
-
-- @Override
-- @Test
-- public void testMutualAuthInvalidIntermediateCASucceedWithOptionalClientAuth() throws Exception {
-- checkShouldUseKeyManagerFactory();
-- super.testMutualAuthInvalidIntermediateCASucceedWithOptionalClientAuth();
+- private ByteBuffer[] singleSrcBuffer(ByteBuffer src) {
+- singleSrcBuffer[0] = src;
+- return singleSrcBuffer;
- }
-
-- @Override
-- @Test
-- public void testMutualAuthInvalidIntermediateCAFailWithOptionalClientAuth() throws Exception {
-- checkShouldUseKeyManagerFactory();
-- super.testMutualAuthInvalidIntermediateCAFailWithOptionalClientAuth();
+- private void resetSingleSrcBuffer() {
+- singleSrcBuffer[0] = null;
- }
-
-- @Override
-- @Test
-- public void testMutualAuthInvalidIntermediateCAFailWithRequiredClientAuth() throws Exception {
-- checkShouldUseKeyManagerFactory();
-- super.testMutualAuthInvalidIntermediateCAFailWithRequiredClientAuth();
+- private ByteBuffer[] singleDstBuffer(ByteBuffer src) {
+- singleDstBuffer[0] = src;
+- return singleDstBuffer;
- }
-
-- @Override
-- @Test
-- public void testMutualAuthValidClientCertChainTooLongFailOptionalClientAuth() throws Exception {
-- checkShouldUseKeyManagerFactory();
-- super.testMutualAuthValidClientCertChainTooLongFailOptionalClientAuth();
+- private void resetSingleDstBuffer() {
+- singleDstBuffer[0] = null;
- }
-
- @Override
-- @Test
-- public void testMutualAuthValidClientCertChainTooLongFailRequireClientAuth() throws Exception {
-- checkShouldUseKeyManagerFactory();
-- super.testMutualAuthValidClientCertChainTooLongFailRequireClientAuth();
+- public final synchronized SSLEngineResult unwrap(
+- final ByteBuffer src, final ByteBuffer[] dsts, final int offset, final int length) throws SSLException {
+- try {
+- return unwrap(singleSrcBuffer(src), 0, 1, dsts, offset, length);
+- } finally {
+- resetSingleSrcBuffer();
+- }
- }
-
- @Override
-- protected void mySetupMutualAuthServerInitSslHandler(SslHandler handler) {
-- ReferenceCountedOpenSslEngine engine = (ReferenceCountedOpenSslEngine) handler.engine();
-- engine.setVerify(SSL_CVERIFY_IGNORED, 1);
+- public final synchronized SSLEngineResult wrap(ByteBuffer src, ByteBuffer dst) throws SSLException {
+- try {
+- return wrap(singleSrcBuffer(src), dst);
+- } finally {
+- resetSingleSrcBuffer();
+- }
- }
-
- @Override
-- protected boolean mySetupMutualAuthServerIsValidClientException(Throwable cause) {
-- // TODO(scott): work around for a JDK issue. The exception should be SSLHandshakeException.
-- return super.mySetupMutualAuthServerIsValidClientException(cause) || causedBySSLException(cause);
-- }
--}
-diff --git a/handler/src/test/java/io/netty/handler/ssl/OpenSslCertificateExceptionTest.java b/handler/src/test/java/io/netty/handler/ssl/OpenSslCertificateExceptionTest.java
-deleted file mode 100644
-index 229e853..0000000
---- a/handler/src/test/java/io/netty/handler/ssl/OpenSslCertificateExceptionTest.java
-+++ /dev/null
-@@ -1,49 +0,0 @@
--/*
-- * Copyright 2017 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
--
--import io.netty.internal.tcnative.CertificateVerifier;
--import org.junit.Assert;
--import org.junit.Assume;
--import org.junit.BeforeClass;
--import org.junit.Test;
--
--import java.lang.reflect.Field;
--
--public class OpenSslCertificateExceptionTest {
--
-- @BeforeClass
-- public static void assumeOpenSsl() {
-- Assume.assumeTrue(OpenSsl.isAvailable());
-- }
--
-- @Test
-- public void testValidErrorCode() throws Exception {
-- Field[] fields = CertificateVerifier.class.getFields();
-- for (Field field : fields) {
-- if (field.isAccessible()) {
-- int errorCode = field.getInt(null);
-- OpenSslCertificateException exception = new OpenSslCertificateException(errorCode);
-- Assert.assertEquals(errorCode, exception.errorCode());
-- }
+- public final synchronized SSLEngineResult unwrap(ByteBuffer src, ByteBuffer dst) throws SSLException {
+- try {
+- return unwrap(singleSrcBuffer(src), singleDstBuffer(dst));
+- } finally {
+- resetSingleSrcBuffer();
+- resetSingleDstBuffer();
- }
- }
-
-- @Test(expected = IllegalArgumentException.class)
-- public void testNonValidErrorCode() {
-- new OpenSslCertificateException(Integer.MIN_VALUE);
-- }
--}
-diff --git a/handler/src/test/java/io/netty/handler/ssl/OpenSslClientContextTest.java b/handler/src/test/java/io/netty/handler/ssl/OpenSslClientContextTest.java
-deleted file mode 100644
-index 6011cf7..0000000
---- a/handler/src/test/java/io/netty/handler/ssl/OpenSslClientContextTest.java
-+++ /dev/null
-@@ -1,38 +0,0 @@
--/*
-- * Copyright 2016 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
--
--import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
--import org.junit.BeforeClass;
--
--import javax.net.ssl.SSLException;
--import java.io.File;
--
--import static org.junit.Assume.assumeTrue;
--
--public class OpenSslClientContextTest extends SslContextTest {
--
-- @BeforeClass
-- public static void checkOpenSsl() {
-- assumeTrue(OpenSsl.isAvailable());
-- }
--
- @Override
-- protected SslContext newServerContext(File crtFile, File keyFile, String pass) throws SSLException {
-- return new OpenSslClientContext(crtFile, InsecureTrustManagerFactory.INSTANCE, crtFile, keyFile, pass,
-- null, null, IdentityCipherSuiteFilter.INSTANCE, ApplicationProtocolConfig.DISABLED, 0, 0);
-- }
--}
-diff --git a/handler/src/test/java/io/netty/handler/ssl/OpenSslEngineTest.java b/handler/src/test/java/io/netty/handler/ssl/OpenSslEngineTest.java
-deleted file mode 100644
-index 5939b66..0000000
---- a/handler/src/test/java/io/netty/handler/ssl/OpenSslEngineTest.java
-+++ /dev/null
-@@ -1,661 +0,0 @@
--/*
-- * Copyright 2015 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
--
--import io.netty.buffer.UnpooledByteBufAllocator;
--import io.netty.handler.ssl.ApplicationProtocolConfig.Protocol;
--import io.netty.handler.ssl.ApplicationProtocolConfig.SelectedListenerFailureBehavior;
--import io.netty.handler.ssl.ApplicationProtocolConfig.SelectorFailureBehavior;
--import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
--import io.netty.handler.ssl.util.SelfSignedCertificate;
--import io.netty.util.internal.PlatformDependent;
--import org.junit.Assume;
--import org.junit.BeforeClass;
--import org.junit.Test;
--import org.junit.runner.RunWith;
--import org.junit.runners.Parameterized;
--
--import java.nio.ByteBuffer;
--import java.security.AlgorithmConstraints;
--import java.security.AlgorithmParameters;
--import java.security.CryptoPrimitive;
--import java.security.Key;
--import java.util.ArrayList;
--import java.util.Collection;
--import java.util.List;
--import java.util.Set;
--import javax.net.ssl.SSLEngine;
--import javax.net.ssl.SSLEngineResult;
--import javax.net.ssl.SSLException;
--import javax.net.ssl.SSLParameters;
--
--import static io.netty.handler.ssl.OpenSslTestUtils.checkShouldUseKeyManagerFactory;
--import static io.netty.handler.ssl.ReferenceCountedOpenSslEngine.MAX_ENCRYPTED_PACKET_LENGTH;
--import static io.netty.handler.ssl.ReferenceCountedOpenSslEngine.MAX_TLS_RECORD_OVERHEAD_LENGTH;
--import static io.netty.handler.ssl.ReferenceCountedOpenSslEngine.MAX_PLAINTEXT_LENGTH;
--import static io.netty.internal.tcnative.SSL.SSL_CVERIFY_IGNORED;
--import static java.lang.Integer.MAX_VALUE;
--import static org.junit.Assert.assertEquals;
--import static org.junit.Assert.assertFalse;
--import static org.junit.Assert.assertNull;
--import static org.junit.Assert.assertSame;
--import static org.junit.Assert.assertTrue;
--import static org.junit.Assume.assumeTrue;
--
--(a)RunWith(Parameterized.class)
--public class OpenSslEngineTest extends SSLEngineTest {
-- private static final String PREFERRED_APPLICATION_LEVEL_PROTOCOL = "my-protocol-http2";
-- private static final String FALLBACK_APPLICATION_LEVEL_PROTOCOL = "my-protocol-http1_1";
--
-- @Parameterized.Parameters(name = "{index}: bufferType = {0}")
-- public static Collection<Object> data() {
-- List<Object> params = new ArrayList<Object>();
-- for (BufferType type: BufferType.values()) {
-- params.add(type);
+- public final synchronized SSLEngineResult unwrap(ByteBuffer src, ByteBuffer[] dsts) throws SSLException {
+- try {
+- return unwrap(singleSrcBuffer(src), dsts);
+- } finally {
+- resetSingleSrcBuffer();
- }
-- return params;
-- }
--
-- public OpenSslEngineTest(BufferType type) {
-- super(type);
-- }
--
-- @BeforeClass
-- public static void checkOpenSsl() {
-- assumeTrue(OpenSsl.isAvailable());
- }
-
- @Override
-- @Test
-- public void testMutualAuthInvalidIntermediateCASucceedWithOptionalClientAuth() throws Exception {
-- checkShouldUseKeyManagerFactory();
-- super.testMutualAuthInvalidIntermediateCASucceedWithOptionalClientAuth();
+- public final synchronized Runnable getDelegatedTask() {
+- if (isDestroyed()) {
+- return null;
+- }
+- final Runnable task = SSL.getTask(ssl);
+- if (task == null) {
+- return null;
+- }
+- return new Runnable() {
+- @Override
+- public void run() {
+- if (isDestroyed()) {
+- // The engine was destroyed in the meantime, just return.
+- return;
+- }
+- try {
+- task.run();
+- } finally {
+- // The task was run, reset needTask to false so getHandshakeStatus() returns the correct value.
+- needTask = false;
+- }
+- }
+- };
- }
-
- @Override
-- @Test
-- public void testMutualAuthInvalidIntermediateCAFailWithOptionalClientAuth() throws Exception {
-- checkShouldUseKeyManagerFactory();
-- super.testMutualAuthInvalidIntermediateCAFailWithOptionalClientAuth();
-- }
+- public final synchronized void closeInbound() throws SSLException {
+- if (isInboundDone) {
+- return;
+- }
-
-- @Override
-- @Test
-- public void testMutualAuthInvalidIntermediateCAFailWithRequiredClientAuth() throws Exception {
-- checkShouldUseKeyManagerFactory();
-- super.testMutualAuthInvalidIntermediateCAFailWithRequiredClientAuth();
-- }
+- isInboundDone = true;
-
-- @Override
-- @Test
-- public void testMutualAuthValidClientCertChainTooLongFailOptionalClientAuth() throws Exception {
-- checkShouldUseKeyManagerFactory();
-- super.testMutualAuthValidClientCertChainTooLongFailOptionalClientAuth();
-- }
+- if (isOutboundDone()) {
+- // Only call shutdown if there is no outbound data pending.
+- // See https://github.com/netty/netty/issues/6167
+- shutdown();
+- }
-
-- @Override
-- @Test
-- public void testMutualAuthValidClientCertChainTooLongFailRequireClientAuth() throws Exception {
-- checkShouldUseKeyManagerFactory();
-- super.testMutualAuthValidClientCertChainTooLongFailRequireClientAuth();
+- if (handshakeState != HandshakeState.NOT_STARTED && !receivedShutdown) {
+- throw new SSLException(
+- "Inbound closed before receiving peer's close_notify: possible truncation attack?");
+- }
- }
-
- @Override
-- @Test
-- public void testClientHostnameValidationSuccess() throws InterruptedException, SSLException {
-- assumeTrue(OpenSsl.supportsHostnameValidation());
-- super.testClientHostnameValidationSuccess();
+- public final synchronized boolean isInboundDone() {
+- return isInboundDone;
- }
-
- @Override
-- @Test
-- public void testClientHostnameValidationFail() throws InterruptedException, SSLException {
-- assumeTrue(OpenSsl.supportsHostnameValidation());
-- super.testClientHostnameValidationFail();
-- }
--
-- @Test
-- public void testNpn() throws Exception {
-- ApplicationProtocolConfig apn = acceptingNegotiator(Protocol.NPN,
-- PREFERRED_APPLICATION_LEVEL_PROTOCOL);
-- setupHandlers(apn);
-- runTest(PREFERRED_APPLICATION_LEVEL_PROTOCOL);
-- }
--
-- @Test
-- public void testAlpn() throws Exception {
-- assumeTrue(OpenSsl.isAlpnSupported());
-- ApplicationProtocolConfig apn = acceptingNegotiator(Protocol.ALPN,
-- PREFERRED_APPLICATION_LEVEL_PROTOCOL);
-- setupHandlers(apn);
-- runTest(PREFERRED_APPLICATION_LEVEL_PROTOCOL);
-- }
--
-- @Test
-- public void testAlpnCompatibleProtocolsDifferentClientOrder() throws Exception {
-- assumeTrue(OpenSsl.isAlpnSupported());
-- ApplicationProtocolConfig clientApn = acceptingNegotiator(Protocol.ALPN,
-- FALLBACK_APPLICATION_LEVEL_PROTOCOL, PREFERRED_APPLICATION_LEVEL_PROTOCOL);
-- ApplicationProtocolConfig serverApn = acceptingNegotiator(Protocol.ALPN,
-- PREFERRED_APPLICATION_LEVEL_PROTOCOL, FALLBACK_APPLICATION_LEVEL_PROTOCOL);
-- setupHandlers(serverApn, clientApn);
-- assertNull(serverException);
-- runTest(PREFERRED_APPLICATION_LEVEL_PROTOCOL);
-- }
--
-- @Test
-- public void testEnablingAnAlreadyDisabledSslProtocol() throws Exception {
-- testEnablingAnAlreadyDisabledSslProtocol(new String[]{PROTOCOL_SSL_V2_HELLO},
-- new String[]{PROTOCOL_SSL_V2_HELLO, PROTOCOL_TLS_V1_2});
-- }
-- @Test
-- public void testWrapBuffersNoWritePendingError() throws Exception {
-- clientSslCtx = SslContextBuilder.forClient()
-- .trustManager(InsecureTrustManagerFactory.INSTANCE)
-- .sslProvider(sslClientProvider())
-- .build();
-- SelfSignedCertificate ssc = new SelfSignedCertificate();
-- serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey())
-- .sslProvider(sslServerProvider())
-- .build();
-- SSLEngine clientEngine = null;
-- SSLEngine serverEngine = null;
-- try {
-- clientEngine = clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT);
-- serverEngine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT);
-- handshake(clientEngine, serverEngine);
--
-- ByteBuffer src = allocateBuffer(1024 * 10);
-- byte[] data = new byte[src.capacity()];
-- PlatformDependent.threadLocalRandom().nextBytes(data);
-- src.put(data).flip();
-- ByteBuffer dst = allocateBuffer(1);
-- // Try to wrap multiple times so we are more likely to hit the issue.
-- for (int i = 0; i < 100; i++) {
-- src.position(0);
-- dst.position(0);
-- assertSame(SSLEngineResult.Status.BUFFER_OVERFLOW, clientEngine.wrap(src, dst).getStatus());
-- }
-- } finally {
-- cleanupClientSslEngine(clientEngine);
-- cleanupServerSslEngine(serverEngine);
-- }
-- }
--
-- @Test
-- public void testOnlySmallBufferNeededForWrap() throws Exception {
-- clientSslCtx = SslContextBuilder.forClient()
-- .trustManager(InsecureTrustManagerFactory.INSTANCE)
-- .sslProvider(sslClientProvider())
-- .build();
-- SelfSignedCertificate ssc = new SelfSignedCertificate();
-- serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey())
-- .sslProvider(sslServerProvider())
-- .build();
-- SSLEngine clientEngine = null;
-- SSLEngine serverEngine = null;
-- try {
-- clientEngine = clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT);
-- serverEngine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT);
-- handshake(clientEngine, serverEngine);
--
-- // Allocate a buffer which is small enough and set the limit to the capacity to mark its whole content
-- // as readable.
-- int srcLen = 1024;
-- ByteBuffer src = allocateBuffer(srcLen);
--
-- ByteBuffer dstTooSmall = allocateBuffer(
-- src.capacity() + MAX_TLS_RECORD_OVERHEAD_LENGTH - 1);
-- ByteBuffer dst = allocateBuffer(
-- src.capacity() + MAX_TLS_RECORD_OVERHEAD_LENGTH);
--
-- // Check that we fail to wrap if the dst buffers capacity is not at least
-- // src.capacity() + ReferenceCountedOpenSslEngine.MAX_TLS_RECORD_OVERHEAD_LENGTH
-- SSLEngineResult result = clientEngine.wrap(src, dstTooSmall);
-- assertEquals(SSLEngineResult.Status.BUFFER_OVERFLOW, result.getStatus());
-- assertEquals(0, result.bytesConsumed());
-- assertEquals(0, result.bytesProduced());
-- assertEquals(src.remaining(), src.capacity());
-- assertEquals(dst.remaining(), dst.capacity());
--
-- // Check that we can wrap with a dst buffer that has the capacity of
-- // src.capacity() + ReferenceCountedOpenSslEngine.MAX_TLS_RECORD_OVERHEAD_LENGTH
-- result = clientEngine.wrap(src, dst);
-- assertEquals(SSLEngineResult.Status.OK, result.getStatus());
-- assertEquals(srcLen, result.bytesConsumed());
-- assertEquals(0, src.remaining());
-- assertTrue(result.bytesProduced() > srcLen);
-- assertEquals(src.capacity() - result.bytesConsumed(), src.remaining());
-- assertEquals(dst.capacity() - result.bytesProduced(), dst.remaining());
-- } finally {
-- cleanupClientSslEngine(clientEngine);
-- cleanupServerSslEngine(serverEngine);
-- }
-- }
--
-- @Test
-- public void testNeededDstCapacityIsCorrectlyCalculated() throws Exception {
-- clientSslCtx = SslContextBuilder.forClient()
-- .trustManager(InsecureTrustManagerFactory.INSTANCE)
-- .sslProvider(sslClientProvider())
-- .build();
-- SelfSignedCertificate ssc = new SelfSignedCertificate();
-- serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey())
-- .sslProvider(sslServerProvider())
-- .build();
-- SSLEngine clientEngine = null;
-- SSLEngine serverEngine = null;
-- try {
-- clientEngine = clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT);
-- serverEngine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT);
-- handshake(clientEngine, serverEngine);
--
-- ByteBuffer src = allocateBuffer(1024);
-- ByteBuffer src2 = src.duplicate();
--
-- ByteBuffer dst = allocateBuffer(src.capacity()
-- + MAX_TLS_RECORD_OVERHEAD_LENGTH);
--
-- SSLEngineResult result = clientEngine.wrap(new ByteBuffer[] { src, src2 }, dst);
-- assertEquals(SSLEngineResult.Status.BUFFER_OVERFLOW, result.getStatus());
-- assertEquals(0, src.position());
-- assertEquals(0, src2.position());
-- assertEquals(0, dst.position());
-- assertEquals(0, result.bytesConsumed());
-- assertEquals(0, result.bytesProduced());
-- } finally {
-- cleanupClientSslEngine(clientEngine);
-- cleanupServerSslEngine(serverEngine);
-- }
-- }
--
-- @Test
-- public void testSrcsLenOverFlowCorrectlyHandled() throws Exception {
-- clientSslCtx = SslContextBuilder.forClient()
-- .trustManager(InsecureTrustManagerFactory.INSTANCE)
-- .sslProvider(sslClientProvider())
-- .build();
-- SelfSignedCertificate ssc = new SelfSignedCertificate();
-- serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey())
-- .sslProvider(sslServerProvider())
-- .build();
-- SSLEngine clientEngine = null;
-- SSLEngine serverEngine = null;
-- try {
-- clientEngine = clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT);
-- serverEngine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT);
-- handshake(clientEngine, serverEngine);
+- public final synchronized void closeOutbound() {
+- if (outboundClosed) {
+- return;
+- }
-
-- ByteBuffer src = allocateBuffer(1024);
-- List<ByteBuffer> srcList = new ArrayList<ByteBuffer>();
-- long srcsLen = 0;
-- long maxLen = ((long) MAX_VALUE) * 2;
+- outboundClosed = true;
-
-- while (srcsLen < maxLen) {
-- ByteBuffer dup = src.duplicate();
-- srcList.add(dup);
-- srcsLen += dup.capacity();
+- if (handshakeState != HandshakeState.NOT_STARTED && !isDestroyed()) {
+- int mode = SSL.getShutdown(ssl);
+- if ((mode & SSL.SSL_SENT_SHUTDOWN) != SSL.SSL_SENT_SHUTDOWN) {
+- doSSLShutdown();
- }
+- } else {
+- // engine closing before initial handshake
+- shutdown();
+- }
+- }
-
-- ByteBuffer[] srcs = srcList.toArray(new ByteBuffer[srcList.size()]);
--
-- ByteBuffer dst = allocateBuffer(MAX_ENCRYPTED_PACKET_LENGTH - 1);
--
-- SSLEngineResult result = clientEngine.wrap(srcs, dst);
-- assertEquals(SSLEngineResult.Status.BUFFER_OVERFLOW, result.getStatus());
--
-- for (ByteBuffer buffer : srcs) {
-- assertEquals(0, buffer.position());
+- /**
+- * Attempt to call {@link SSL#shutdownSSL(long)}.
+- * @return {@code false} if the call to {@link SSL#shutdownSSL(long)} was not attempted or returned an error.
+- */
+- private boolean doSSLShutdown() {
+- if (SSL.isInInit(ssl) != 0) {
+- // Only try to call SSL_shutdown if we are not in the init state anymore.
+- // Otherwise we will see 'error:140E0197:SSL routines:SSL_shutdown:shutdown while in init' in our logs.
+- //
+- // See also http://hg.nginx.org/nginx/rev/062c189fee20
+- return false;
+- }
+- int err = SSL.shutdownSSL(ssl);
+- if (err < 0) {
+- int sslErr = SSL.getError(ssl, err);
+- if (sslErr == SSL.SSL_ERROR_SYSCALL || sslErr == SSL.SSL_ERROR_SSL) {
+- if (logger.isDebugEnabled()) {
+- int error = SSL.getLastErrorNumber();
+- logger.debug("SSL_shutdown failed: OpenSSL error: {} {}", error, SSL.getErrorString(error));
+- }
+- // There was an internal error -- shutdown
+- shutdown();
+- return false;
- }
-- assertEquals(0, dst.position());
-- assertEquals(0, result.bytesConsumed());
-- assertEquals(0, result.bytesProduced());
-- } finally {
-- cleanupClientSslEngine(clientEngine);
-- cleanupServerSslEngine(serverEngine);
+- SSL.clearError();
- }
+- return true;
- }
-
-- @Test
-- public void testCalculateOutNetBufSizeOverflow() {
-- assertEquals(MAX_ENCRYPTED_PACKET_LENGTH,
-- ReferenceCountedOpenSslEngine.calculateOutNetBufSize(MAX_VALUE, 1));
-- }
--
-- @Test
-- public void testCalculateOutNetBufSize0() {
-- assertEquals(MAX_TLS_RECORD_OVERHEAD_LENGTH,
-- ReferenceCountedOpenSslEngine.calculateOutNetBufSize(0, 1));
+- @Override
+- public final synchronized boolean isOutboundDone() {
+- // Check if there is anything left in the outbound buffer.
+- // We need to ensure we only call SSL.pendingWrittenBytesInBIO(...) if the engine was not destroyed yet.
+- return outboundClosed && (networkBIO == 0 || SSL.bioLengthNonApplication(networkBIO) == 0);
- }
-
-- @Test
-- public void testCalculateOutNetBufSizeMaxEncryptedPacketLength() {
-- assertEquals(MAX_ENCRYPTED_PACKET_LENGTH,
-- ReferenceCountedOpenSslEngine.calculateOutNetBufSize(MAX_ENCRYPTED_PACKET_LENGTH + 1, 2));
+- @Override
+- public final String[] getSupportedCipherSuites() {
+- return OpenSsl.AVAILABLE_CIPHER_SUITES.toArray(new String[0]);
- }
-
- @Override
-- protected void mySetupMutualAuthServerInitSslHandler(SslHandler handler) {
-- ReferenceCountedOpenSslEngine engine = (ReferenceCountedOpenSslEngine) handler.engine();
-- engine.setVerify(SSL_CVERIFY_IGNORED, 1);
-- }
--
-- @Test
-- public void testWrapWithDifferentSizesTLSv1() throws Exception {
-- clientSslCtx = SslContextBuilder.forClient()
-- .trustManager(InsecureTrustManagerFactory.INSTANCE)
-- .sslProvider(sslClientProvider())
-- .build();
-- SelfSignedCertificate ssc = new SelfSignedCertificate();
-- serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey())
-- .sslProvider(sslServerProvider())
-- .build();
--
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ADH-AES128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "AES128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ECDHE-RSA-AES128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ADH-CAMELLIA128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "AECDH-AES128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "AECDH-DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "CAMELLIA128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "DHE-RSA-AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "SEED-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "RC4-MD5");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ADH-AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ADH-SEED-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ADH-DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "EDH-RSA-DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ADH-RC4-MD5");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "IDEA-CBC-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "DHE-RSA-AES128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "RC4-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "CAMELLIA256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "AECDH-RC4-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "DHE-RSA-SEED-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "AECDH-AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ECDHE-RSA-DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ADH-CAMELLIA256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "DHE-RSA-CAMELLIA256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ECDHE-RSA-AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "DHE-RSA-CAMELLIA128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1, "ECDHE-RSA-RC4-SHA");
-- }
--
-- @Test
-- public void testWrapWithDifferentSizesTLSv1_1() throws Exception {
-- clientSslCtx = SslContextBuilder.forClient()
-- .trustManager(InsecureTrustManagerFactory.INSTANCE)
-- .sslProvider(sslClientProvider())
-- .build();
-- SelfSignedCertificate ssc = new SelfSignedCertificate();
-- serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey())
-- .sslProvider(sslServerProvider())
-- .build();
--
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "ECDHE-RSA-AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "DHE-RSA-AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "DHE-RSA-CAMELLIA256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "ADH-CAMELLIA256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "ADH-AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "CAMELLIA256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "AECDH-AES128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "DHE-RSA-CAMELLIA128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "ECDHE-RSA-AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "ADH-AES128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "ADH-SEED-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "ADH-CAMELLIA128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "SEED-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "CAMELLIA128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "IDEA-CBC-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "AECDH-RC4-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "ADH-RC4-MD5");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "RC4-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "ECDHE-RSA-DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "EDH-RSA-DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "AECDH-DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "ADH-DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_1, "DES-CBC3-SHA");
-- }
--
-- @Test
-- public void testWrapWithDifferentSizesTLSv1_2() throws Exception {
-- clientSslCtx = SslContextBuilder.forClient()
-- .trustManager(InsecureTrustManagerFactory.INSTANCE)
-- .sslProvider(sslClientProvider())
-- .build();
-- SelfSignedCertificate ssc = new SelfSignedCertificate();
-- serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey())
-- .sslProvider(sslServerProvider())
-- .build();
--
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ADH-AES128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "AES128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ECDHE-RSA-AES128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ADH-CAMELLIA128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "DHE-RSA-AES256-GCM-SHA384");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "AECDH-AES128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "AES128-GCM-SHA256");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "DHE-RSA-AES128-GCM-SHA256");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ECDHE-RSA-AES256-SHA384");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "AECDH-DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "AES256-GCM-SHA384");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "AES256-SHA256");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ECDHE-RSA-AES128-GCM-SHA256");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ECDHE-RSA-AES128-SHA256");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "CAMELLIA128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "DHE-RSA-AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "SEED-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "RC4-MD5");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ADH-AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ADH-SEED-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "DHE-RSA-AES128-SHA256");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ADH-DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "EDH-RSA-DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ADH-RC4-MD5");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "IDEA-CBC-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "DHE-RSA-AES128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "RC4-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "CAMELLIA256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ADH-AES128-GCM-SHA256");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "AES128-SHA256");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "AECDH-RC4-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ADH-AES256-GCM-SHA384");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "DHE-RSA-SEED-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "DHE-RSA-AES256-SHA256");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "AECDH-AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ECDHE-RSA-DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ADH-CAMELLIA256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ECDHE-RSA-AES256-GCM-SHA384");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "DHE-RSA-CAMELLIA256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ADH-AES256-SHA256");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ADH-AES128-SHA256");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ECDHE-RSA-AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "DHE-RSA-CAMELLIA128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_TLS_V1_2, "ECDHE-RSA-RC4-SHA");
-- }
--
-- @Test
-- public void testWrapWithDifferentSizesSSLv3() throws Exception {
-- clientSslCtx = SslContextBuilder.forClient()
-- .trustManager(InsecureTrustManagerFactory.INSTANCE)
-- .sslProvider(sslClientProvider())
-- .build();
-- SelfSignedCertificate ssc = new SelfSignedCertificate();
-- serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey())
-- .sslProvider(sslServerProvider())
-- .build();
--
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "ADH-AES128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "AES128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "ADH-CAMELLIA128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "AECDH-AES128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "AECDH-DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "CAMELLIA128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "DHE-RSA-AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "SEED-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "RC4-MD5");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "ADH-AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "ADH-SEED-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "ADH-DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "EDH-RSA-DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "ADH-RC4-MD5");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "IDEA-CBC-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "DHE-RSA-AES128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "RC4-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "CAMELLIA256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "AECDH-RC4-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "DHE-RSA-SEED-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "AECDH-AES256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "ECDHE-RSA-DES-CBC3-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "ADH-CAMELLIA256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "DHE-RSA-CAMELLIA256-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "DHE-RSA-CAMELLIA128-SHA");
-- testWrapWithDifferentSizes(OpenSsl.PROTOCOL_SSL_V3, "ECDHE-RSA-RC4-SHA");
-- }
--
-- private void testWrapWithDifferentSizes(String protocol, String cipher) throws Exception {
-- assumeTrue(OpenSsl.SUPPORTED_PROTOCOLS_SET.contains(protocol));
-- if (!OpenSsl.isCipherSuiteAvailable(cipher)) {
-- return;
+- public final String[] getEnabledCipherSuites() {
+- final String[] extraCiphers;
+- final String[] enabled;
+- synchronized (this) {
+- if (!isDestroyed()) {
+- enabled = SSL.getCiphers(ssl);
+- int opts = SSL.getOptions(ssl);
+- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_TLSv1_3, PROTOCOL_TLS_V1_3)) {
+- extraCiphers = OpenSsl.EXTRA_SUPPORTED_TLS_1_3_CIPHERS;
+- } else {
+- extraCiphers = EmptyArrays.EMPTY_STRINGS;
+- }
+- } else {
+- return EmptyArrays.EMPTY_STRINGS;
+- }
- }
--
-- SSLEngine clientEngine = null;
-- SSLEngine serverEngine = null;
-- try {
-- clientEngine = clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT);
-- serverEngine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT);
-- clientEngine.setEnabledCipherSuites(new String[] { cipher });
-- clientEngine.setEnabledProtocols(new String[] { protocol });
-- serverEngine.setEnabledCipherSuites(new String[] { cipher });
-- serverEngine.setEnabledProtocols(new String[] { protocol });
--
-- try {
-- handshake(clientEngine, serverEngine);
-- } catch (SSLException e) {
-- if (e.getMessage().contains("unsupported protocol")) {
-- Assume.assumeNoException(protocol + " not supported with cipher " + cipher, e);
+- if (enabled == null) {
+- return EmptyArrays.EMPTY_STRINGS;
+- } else {
+- Set<String> enabledSet = new LinkedHashSet<String>(enabled.length + extraCiphers.length);
+- synchronized (this) {
+- for (int i = 0; i < enabled.length; i++) {
+- String mapped = toJavaCipherSuite(enabled[i]);
+- final String cipher = mapped == null ? enabled[i] : mapped;
+- if (!OpenSsl.isTlsv13Supported() && SslUtils.isTLSv13Cipher(cipher)) {
+- continue;
+- }
+- enabledSet.add(cipher);
- }
-- throw e;
+- Collections.addAll(enabledSet, extraCiphers);
- }
--
-- int srcLen = 64;
-- do {
-- testWrapDstBigEnough(clientEngine, srcLen);
-- srcLen += 64;
-- } while (srcLen < MAX_PLAINTEXT_LENGTH);
--
-- testWrapDstBigEnough(clientEngine, MAX_PLAINTEXT_LENGTH);
-- } finally {
-- cleanupClientSslEngine(clientEngine);
-- cleanupServerSslEngine(serverEngine);
+- return enabledSet.toArray(new String[0]);
- }
- }
-
-- private void testWrapDstBigEnough(SSLEngine engine, int srcLen) throws SSLException {
-- ByteBuffer src = allocateBuffer(srcLen);
-- ByteBuffer dst = allocateBuffer(srcLen + MAX_TLS_RECORD_OVERHEAD_LENGTH);
--
-- SSLEngineResult result = engine.wrap(src, dst);
-- assertEquals(SSLEngineResult.Status.OK, result.getStatus());
-- int consumed = result.bytesConsumed();
-- int produced = result.bytesProduced();
-- assertEquals(srcLen, consumed);
-- assertTrue(produced > consumed);
+- @Override
+- public final void setEnabledCipherSuites(String[] cipherSuites) {
+- checkNotNull(cipherSuites, "cipherSuites");
-
-- dst.flip();
-- assertEquals(produced, dst.remaining());
-- assertFalse(src.hasRemaining());
-- }
+- final StringBuilder buf = new StringBuilder();
+- final StringBuilder bufTLSv13 = new StringBuilder();
-
-- @Test
-- public void testSNIMatchersDoesNotThrow() throws Exception {
-- assumeTrue(PlatformDependent.javaVersion() >= 8);
-- SelfSignedCertificate ssc = new SelfSignedCertificate();
-- serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey())
-- .sslProvider(sslServerProvider())
-- .build();
+- CipherSuiteConverter.convertToCipherStrings(Arrays.asList(cipherSuites), buf, bufTLSv13, OpenSsl.isBoringSSL());
+- final String cipherSuiteSpec = buf.toString();
+- final String cipherSuiteSpecTLSv13 = bufTLSv13.toString();
-
-- SSLEngine engine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT);
-- try {
-- SSLParameters parameters = new SSLParameters();
-- Java8SslTestUtils.setSNIMatcher(parameters);
-- engine.setSSLParameters(parameters);
-- } finally {
-- cleanupServerSslEngine(engine);
-- ssc.delete();
+- if (!OpenSsl.isTlsv13Supported() && !cipherSuiteSpecTLSv13.isEmpty()) {
+- throw new IllegalArgumentException("TLSv1.3 is not supported by this java version.");
- }
-- }
--
-- @Test(expected = IllegalArgumentException.class)
-- public void testAlgorithmConstraintsThrows() throws Exception {
-- SelfSignedCertificate ssc = new SelfSignedCertificate();
-- serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey())
-- .sslProvider(sslServerProvider())
-- .build();
--
-- SSLEngine engine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT);
-- try {
-- SSLParameters parameters = new SSLParameters();
-- parameters.setAlgorithmConstraints(new AlgorithmConstraints() {
-- @Override
-- public boolean permits(
-- Set<CryptoPrimitive> primitives, String algorithm, AlgorithmParameters parameters) {
-- return false;
-- }
+- synchronized (this) {
+- if (!isDestroyed()) {
+- // TODO: Should we also adjust the protocols based on if there are any ciphers left that can be used
+- // for TLSv1.3 or for previor SSL/TLS versions ?
+- try {
+- // Set non TLSv1.3 ciphers.
+- SSL.setCipherSuites(ssl, cipherSuiteSpec, false);
-
-- @Override
-- public boolean permits(Set<CryptoPrimitive> primitives, Key key) {
-- return false;
-- }
+- if (OpenSsl.isTlsv13Supported()) {
+- // Set TLSv1.3 ciphers.
+- SSL.setCipherSuites(ssl, cipherSuiteSpecTLSv13, true);
+- }
-
-- @Override
-- public boolean permits(
-- Set<CryptoPrimitive> primitives, String algorithm, Key key, AlgorithmParameters parameters) {
-- return false;
+- } catch (Exception e) {
+- throw new IllegalStateException("failed to enable cipher suites: " + cipherSuiteSpec, e);
- }
-- });
-- engine.setSSLParameters(parameters);
-- } finally {
-- cleanupServerSslEngine(engine);
-- ssc.delete();
+- } else {
+- throw new IllegalStateException("failed to enable cipher suites: " + cipherSuiteSpec);
+- }
- }
- }
-
- @Override
-- protected SslProvider sslClientProvider() {
-- return SslProvider.OPENSSL;
+- public final String[] getSupportedProtocols() {
+- return OpenSsl.SUPPORTED_PROTOCOLS_SET.toArray(new String[0]);
- }
-
- @Override
-- protected SslProvider sslServerProvider() {
-- return SslProvider.OPENSSL;
-- }
--
-- private static ApplicationProtocolConfig acceptingNegotiator(Protocol protocol,
-- String... supportedProtocols) {
-- return new ApplicationProtocolConfig(protocol,
-- SelectorFailureBehavior.NO_ADVERTISE,
-- SelectedListenerFailureBehavior.ACCEPT,
-- supportedProtocols);
-- }
--}
-diff --git a/handler/src/test/java/io/netty/handler/ssl/OpenSslJdkSslEngineInteroptTest.java b/handler/src/test/java/io/netty/handler/ssl/OpenSslJdkSslEngineInteroptTest.java
-deleted file mode 100644
-index f63a16f..0000000
---- a/handler/src/test/java/io/netty/handler/ssl/OpenSslJdkSslEngineInteroptTest.java
-+++ /dev/null
-@@ -1,114 +0,0 @@
--/*
-- * Copyright 2016 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
--
--import org.junit.BeforeClass;
--import org.junit.Ignore;
--import org.junit.Test;
--
--import javax.net.ssl.SSLException;
--import org.junit.runner.RunWith;
--import org.junit.runners.Parameterized;
--
--import java.util.ArrayList;
--import java.util.Collection;
--import java.util.List;
--
--import static io.netty.handler.ssl.OpenSslTestUtils.checkShouldUseKeyManagerFactory;
--import static org.junit.Assume.assumeTrue;
--
--(a)RunWith(Parameterized.class)
--public class OpenSslJdkSslEngineInteroptTest extends SSLEngineTest {
+- public final String[] getEnabledProtocols() {
+- List<String> enabled = new ArrayList<String>(6);
+- // Seems like there is no way to explicit disable SSLv2Hello in openssl so it is always enabled
+- enabled.add(PROTOCOL_SSL_V2_HELLO);
-
-- @Parameterized.Parameters(name = "{index}: bufferType = {0}")
-- public static Collection<Object> data() {
-- List<Object> params = new ArrayList<Object>();
-- for (BufferType type: BufferType.values()) {
-- params.add(type);
+- int opts;
+- synchronized (this) {
+- if (!isDestroyed()) {
+- opts = SSL.getOptions(ssl);
+- } else {
+- return enabled.toArray(new String[0]);
+- }
- }
-- return params;
-- }
--
-- public OpenSslJdkSslEngineInteroptTest(BufferType type) {
-- super(type);
+- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_TLSv1, PROTOCOL_TLS_V1)) {
+- enabled.add(PROTOCOL_TLS_V1);
+- }
+- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_TLSv1_1, PROTOCOL_TLS_V1_1)) {
+- enabled.add(PROTOCOL_TLS_V1_1);
+- }
+- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_TLSv1_2, PROTOCOL_TLS_V1_2)) {
+- enabled.add(PROTOCOL_TLS_V1_2);
+- }
+- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_TLSv1_3, PROTOCOL_TLS_V1_3)) {
+- enabled.add(PROTOCOL_TLS_V1_3);
+- }
+- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_SSLv2, PROTOCOL_SSL_V2)) {
+- enabled.add(PROTOCOL_SSL_V2);
+- }
+- if (isProtocolEnabled(opts, SSL.SSL_OP_NO_SSLv3, PROTOCOL_SSL_V3)) {
+- enabled.add(PROTOCOL_SSL_V3);
+- }
+- return enabled.toArray(new String[0]);
- }
-
-- @BeforeClass
-- public static void checkOpenSsl() {
-- assumeTrue(OpenSsl.isAvailable());
+- private static boolean isProtocolEnabled(int opts, int disableMask, String protocolString) {
+- // We also need to check if the actual protocolString is supported as depending on the openssl API
+- // implementations it may use a disableMask of 0 (BoringSSL is doing this for example).
+- return (opts & disableMask) == 0 && OpenSsl.SUPPORTED_PROTOCOLS_SET.contains(protocolString);
- }
-
+- /**
+- * {@inheritDoc}
+- * TLS doesn't support a way to advertise non-contiguous versions from the client's perspective, and the client
+- * just advertises the max supported version. The TLS protocol also doesn't support all different combinations of
+- * discrete protocols, and instead assumes contiguous ranges. OpenSSL has some unexpected behavior
+- * (e.g. handshake failures) if non-contiguous protocols are used even where there is a compatible set of protocols
+- * and ciphers. For these reasons this method will determine the minimum protocol and the maximum protocol and
+- * enabled a contiguous range from [min protocol, max protocol] in OpenSSL.
+- */
- @Override
-- protected SslProvider sslClientProvider() {
-- return SslProvider.OPENSSL;
-- }
+- public final void setEnabledProtocols(String[] protocols) {
+- if (protocols == null) {
+- // This is correct from the API docs
+- throw new IllegalArgumentException();
+- }
+- int minProtocolIndex = OPENSSL_OP_NO_PROTOCOLS.length;
+- int maxProtocolIndex = 0;
+- for (String p: protocols) {
+- if (!OpenSsl.SUPPORTED_PROTOCOLS_SET.contains(p)) {
+- throw new IllegalArgumentException("Protocol " + p + " is not supported.");
+- }
+- if (p.equals(PROTOCOL_SSL_V2)) {
+- if (minProtocolIndex > OPENSSL_OP_NO_PROTOCOL_INDEX_SSLV2) {
+- minProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_SSLV2;
+- }
+- if (maxProtocolIndex < OPENSSL_OP_NO_PROTOCOL_INDEX_SSLV2) {
+- maxProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_SSLV2;
+- }
+- } else if (p.equals(PROTOCOL_SSL_V3)) {
+- if (minProtocolIndex > OPENSSL_OP_NO_PROTOCOL_INDEX_SSLV3) {
+- minProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_SSLV3;
+- }
+- if (maxProtocolIndex < OPENSSL_OP_NO_PROTOCOL_INDEX_SSLV3) {
+- maxProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_SSLV3;
+- }
+- } else if (p.equals(PROTOCOL_TLS_V1)) {
+- if (minProtocolIndex > OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1) {
+- minProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1;
+- }
+- if (maxProtocolIndex < OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1) {
+- maxProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1;
+- }
+- } else if (p.equals(PROTOCOL_TLS_V1_1)) {
+- if (minProtocolIndex > OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_1) {
+- minProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_1;
+- }
+- if (maxProtocolIndex < OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_1) {
+- maxProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_1;
+- }
+- } else if (p.equals(PROTOCOL_TLS_V1_2)) {
+- if (minProtocolIndex > OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_2) {
+- minProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_2;
+- }
+- if (maxProtocolIndex < OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_2) {
+- maxProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_2;
+- }
+- } else if (p.equals(PROTOCOL_TLS_V1_3)) {
+- if (minProtocolIndex > OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_3) {
+- minProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_3;
+- }
+- if (maxProtocolIndex < OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_3) {
+- maxProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_3;
+- }
+- }
+- }
+- synchronized (this) {
+- if (!isDestroyed()) {
+- // Clear out options which disable protocols
+- SSL.clearOptions(ssl, SSL.SSL_OP_NO_SSLv2 | SSL.SSL_OP_NO_SSLv3 | SSL.SSL_OP_NO_TLSv1 |
+- SSL.SSL_OP_NO_TLSv1_1 | SSL.SSL_OP_NO_TLSv1_2 | SSL.SSL_OP_NO_TLSv1_3);
-
-- @Override
-- protected SslProvider sslServerProvider() {
-- return SslProvider.JDK;
-- }
+- int opts = 0;
+- for (int i = 0; i < minProtocolIndex; ++i) {
+- opts |= OPENSSL_OP_NO_PROTOCOLS[i];
+- }
+- assert maxProtocolIndex != MAX_VALUE;
+- for (int i = maxProtocolIndex + 1; i < OPENSSL_OP_NO_PROTOCOLS.length; ++i) {
+- opts |= OPENSSL_OP_NO_PROTOCOLS[i];
+- }
-
-- @Ignore /* Does the JDK support a "max certificate chain length"? */
-- @Override
-- public void testMutualAuthValidClientCertChainTooLongFailOptionalClientAuth() throws Exception {
+- // Disable protocols we do not want
+- SSL.setOptions(ssl, opts);
+- } else {
+- throw new IllegalStateException("failed to enable protocols: " + Arrays.asList(protocols));
+- }
+- }
- }
-
-- @Ignore /* Does the JDK support a "max certificate chain length"? */
- @Override
-- public void testMutualAuthValidClientCertChainTooLongFailRequireClientAuth() throws Exception {
+- public final SSLSession getSession() {
+- return session;
- }
-
- @Override
-- @Test
-- public void testMutualAuthInvalidIntermediateCASucceedWithOptionalClientAuth() throws Exception {
-- checkShouldUseKeyManagerFactory();
-- super.testMutualAuthInvalidIntermediateCASucceedWithOptionalClientAuth();
-- }
+- public final synchronized void beginHandshake() throws SSLException {
+- switch (handshakeState) {
+- case STARTED_IMPLICITLY:
+- checkEngineClosed();
-
-- @Override
-- @Test
-- public void testMutualAuthInvalidIntermediateCAFailWithOptionalClientAuth() throws Exception {
-- checkShouldUseKeyManagerFactory();
-- super.testMutualAuthInvalidIntermediateCAFailWithOptionalClientAuth();
-- }
+- // A user did not start handshake by calling this method by him/herself,
+- // but handshake has been started already by wrap() or unwrap() implicitly.
+- // Because it's the user's first time to call this method, it is unfair to
+- // raise an exception. From the user's standpoint, he or she never asked
+- // for renegotiation.
-
-- @Override
-- @Test
-- public void testMutualAuthInvalidIntermediateCAFailWithRequiredClientAuth() throws Exception {
-- checkShouldUseKeyManagerFactory();
-- super.testMutualAuthInvalidIntermediateCAFailWithRequiredClientAuth();
+- handshakeState = HandshakeState.STARTED_EXPLICITLY; // Next time this method is invoked by the user,
+- calculateMaxWrapOverhead();
+- // we should raise an exception.
+- break;
+- case STARTED_EXPLICITLY:
+- // Nothing to do as the handshake is not done yet.
+- break;
+- case FINISHED:
+- throw new SSLException("renegotiation unsupported");
+- case NOT_STARTED:
+- handshakeState = HandshakeState.STARTED_EXPLICITLY;
+- if (handshake() == NEED_TASK) {
+- // Set needTask to true so getHandshakeStatus() will return the correct value.
+- needTask = true;
+- }
+- calculateMaxWrapOverhead();
+- break;
+- default:
+- throw new Error();
+- }
- }
-
-- @Override
-- @Test
-- public void testClientHostnameValidationSuccess() throws InterruptedException, SSLException {
-- assumeTrue(OpenSsl.supportsHostnameValidation());
-- super.testClientHostnameValidationSuccess();
+- private void checkEngineClosed() throws SSLException {
+- if (isDestroyed()) {
+- throw new SSLException("engine closed");
+- }
- }
-
-- @Override
-- @Test
-- public void testClientHostnameValidationFail() throws InterruptedException, SSLException {
-- assumeTrue(OpenSsl.supportsHostnameValidation());
-- super.testClientHostnameValidationFail();
+- private static SSLEngineResult.HandshakeStatus pendingStatus(int pendingStatus) {
+- // Depending on if there is something left in the BIO we need to WRAP or UNWRAP
+- return pendingStatus > 0 ? NEED_WRAP : NEED_UNWRAP;
- }
-
-- @Override
-- protected boolean mySetupMutualAuthServerIsValidServerException(Throwable cause) {
-- // TODO(scott): work around for a JDK issue. The exception should be SSLHandshakeException.
-- return super.mySetupMutualAuthServerIsValidServerException(cause) || causedBySSLException(cause);
+- private static boolean isEmpty(Object[] arr) {
+- return arr == null || arr.length == 0;
- }
--}
-diff --git a/handler/src/test/java/io/netty/handler/ssl/OpenSslRenegotiateSmallBIOTest.java b/handler/src/test/java/io/netty/handler/ssl/OpenSslRenegotiateSmallBIOTest.java
-deleted file mode 100644
-index 3959e64..0000000
---- a/handler/src/test/java/io/netty/handler/ssl/OpenSslRenegotiateSmallBIOTest.java
-+++ /dev/null
-@@ -1,23 +0,0 @@
--/*
-- * Copyright 2017 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
-
--public class OpenSslRenegotiateSmallBIOTest extends OpenSslRenegotiateTest {
-- @Override
-- protected void initSslServerContext(SslContext context) {
-- ((ReferenceCountedOpenSslContext) context).setBioNonApplicationBufferSize(1);
+- private static boolean isEmpty(byte[] cert) {
+- return cert == null || cert.length == 0;
- }
--}
-diff --git a/handler/src/test/java/io/netty/handler/ssl/OpenSslRenegotiateTest.java b/handler/src/test/java/io/netty/handler/ssl/OpenSslRenegotiateTest.java
-deleted file mode 100644
-index 8f3dfee..0000000
---- a/handler/src/test/java/io/netty/handler/ssl/OpenSslRenegotiateTest.java
-+++ /dev/null
-@@ -1,36 +0,0 @@
--/*
-- * Copyright 2015 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
-
--import org.junit.BeforeClass;
+- private SSLEngineResult.HandshakeStatus handshakeException() throws SSLException {
+- if (SSL.bioLengthNonApplication(networkBIO) > 0) {
+- // There is something pending, we need to consume it first via a WRAP so we don't loose anything.
+- return NEED_WRAP;
+- }
+-
+- Throwable exception = pendingException;
+- assert exception != null;
+- pendingException = null;
+- shutdown();
+- if (exception instanceof SSLHandshakeException) {
+- throw (SSLHandshakeException) exception;
+- }
+- SSLHandshakeException e = new SSLHandshakeException("General OpenSslEngine problem");
+- e.initCause(exception);
+- throw e;
+- }
-
--import static org.junit.Assume.assumeFalse;
--import static org.junit.Assume.assumeTrue;
+- /**
+- * Should be called if the handshake will be failed due a callback that throws an exception.
+- * This cause will then be used to give more details as part of the {@link SSLHandshakeException}.
+- */
+- final void initHandshakeException(Throwable cause) {
+- if (pendingException == null) {
+- pendingException = cause;
+- } else {
+- ThrowableUtil.addSuppressed(pendingException, cause);
+- }
+- }
-
--public class OpenSslRenegotiateTest extends RenegotiateTest {
+- private SSLEngineResult.HandshakeStatus handshake() throws SSLException {
+- if (needTask) {
+- return NEED_TASK;
+- }
+- if (handshakeState == HandshakeState.FINISHED) {
+- return FINISHED;
+- }
-
-- @BeforeClass
-- public static void checkOpenSsl() {
-- assumeTrue(OpenSsl.isAvailable());
-- // BoringSSL does not support renegotiation intentionally.
-- assumeFalse("BoringSSL".equals(OpenSsl.versionString()));
-- }
+- checkEngineClosed();
-
-- @Override
-- protected SslProvider serverSslProvider() {
-- return SslProvider.OPENSSL;
-- }
--}
-diff --git a/handler/src/test/java/io/netty/handler/ssl/OpenSslServerContextTest.java b/handler/src/test/java/io/netty/handler/ssl/OpenSslServerContextTest.java
-deleted file mode 100644
-index f22d045..0000000
---- a/handler/src/test/java/io/netty/handler/ssl/OpenSslServerContextTest.java
-+++ /dev/null
-@@ -1,39 +0,0 @@
--/*
-- * Copyright 2016 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
+- if (pendingException != null) {
+- // Let's call SSL.doHandshake(...) again in case there is some async operation pending that would fill the
+- // outbound buffer.
+- if (SSL.doHandshake(ssl) <= 0) {
+- // Clear any error that was put on the stack by the handshake
+- SSL.clearError();
+- }
+- return handshakeException();
+- }
-
--package io.netty.handler.ssl;
+- // Adding the OpenSslEngine to the OpenSslEngineMap so it can be used in the AbstractCertificateVerifier.
+- engineMap.add(this);
+- if (lastAccessed == -1) {
+- lastAccessed = System.currentTimeMillis();
+- }
-
--import org.junit.Assume;
--import org.junit.BeforeClass;
+- int code = SSL.doHandshake(ssl);
+- if (code <= 0) {
+- int sslError = SSL.getError(ssl, code);
+- if (sslError == SSL.SSL_ERROR_WANT_READ || sslError == SSL.SSL_ERROR_WANT_WRITE) {
+- return pendingStatus(SSL.bioLengthNonApplication(networkBIO));
+- }
-
--import javax.net.ssl.SSLException;
--import java.io.File;
+- if (sslError == SSL.SSL_ERROR_WANT_X509_LOOKUP ||
+- sslError == SSL.SSL_ERROR_WANT_CERTIFICATE_VERIFY ||
+- sslError == SSL.SSL_ERROR_WANT_PRIVATE_KEY_OPERATION) {
+- return NEED_TASK;
+- }
-
--import static org.junit.Assume.assumeTrue;
+- // Check if we have a pending exception that was created during the handshake and if so throw it after
+- // shutdown the connection.
+- if (pendingException != null) {
+- return handshakeException();
+- }
-
--public class OpenSslServerContextTest extends SslContextTest {
+- // Everything else is considered as error
+- throw shutdownWithError("SSL_do_handshake", sslError);
+- }
+- // We have produced more data as part of the handshake if this is the case the user should call wrap(...)
+- if (SSL.bioLengthNonApplication(networkBIO) > 0) {
+- return NEED_WRAP;
+- }
+- // if SSL_do_handshake returns > 0 or sslError == SSL.SSL_ERROR_NAME it means the handshake was finished.
+- session.handshakeFinished();
+- return FINISHED;
+- }
-
-- @BeforeClass
-- public static void checkOpenSsl() {
-- assumeTrue(OpenSsl.isAvailable());
+- private SSLEngineResult.HandshakeStatus mayFinishHandshake(SSLEngineResult.HandshakeStatus status)
+- throws SSLException {
+- if (status == NOT_HANDSHAKING && handshakeState != HandshakeState.FINISHED) {
+- // If the status was NOT_HANDSHAKING and we not finished the handshake we need to call
+- // SSL_do_handshake() again
+- return handshake();
+- }
+- return status;
- }
-
- @Override
-- protected SslContext newServerContext(File crtFile, File keyFile, String pass) throws SSLException {
-- Assume.assumeTrue(OpenSsl.isAvailable());
-- return new OpenSslServerContext(crtFile, keyFile, pass);
+- public final synchronized SSLEngineResult.HandshakeStatus getHandshakeStatus() {
+- // Check if we are in the initial handshake phase or shutdown phase
+- if (needPendingStatus()) {
+- if (needTask) {
+- // There is a task outstanding
+- return NEED_TASK;
+- }
+- return pendingStatus(SSL.bioLengthNonApplication(networkBIO));
+- }
+- return NOT_HANDSHAKING;
- }
--}
-diff --git a/handler/src/test/java/io/netty/handler/ssl/OpenSslTestUtils.java b/handler/src/test/java/io/netty/handler/ssl/OpenSslTestUtils.java
-deleted file mode 100644
-index 7882a61..0000000
---- a/handler/src/test/java/io/netty/handler/ssl/OpenSslTestUtils.java
-+++ /dev/null
-@@ -1,27 +0,0 @@
--/*
-- * Copyright 2017 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
-
--import static org.junit.Assume.assumeTrue;
--
--final class OpenSslTestUtils {
-- private OpenSslTestUtils() {
+- private SSLEngineResult.HandshakeStatus getHandshakeStatus(int pending) {
+- // Check if we are in the initial handshake phase or shutdown phase
+- if (needPendingStatus()) {
+- if (needTask) {
+- // There is a task outstanding
+- return NEED_TASK;
+- }
+- return pendingStatus(pending);
+- }
+- return NOT_HANDSHAKING;
- }
-
-- static void checkShouldUseKeyManagerFactory() {
-- assumeTrue(OpenSsl.supportsKeyManagerFactory() && OpenSsl.useKeyManagerFactory());
+- private boolean needPendingStatus() {
+- return handshakeState != HandshakeState.NOT_STARTED && !isDestroyed()
+- && (handshakeState != HandshakeState.FINISHED || isInboundDone() || isOutboundDone());
- }
--}
-diff --git a/handler/src/test/java/io/netty/handler/ssl/PemEncodedTest.java b/handler/src/test/java/io/netty/handler/ssl/PemEncodedTest.java
-deleted file mode 100644
-index 793f772..0000000
---- a/handler/src/test/java/io/netty/handler/ssl/PemEncodedTest.java
-+++ /dev/null
-@@ -1,95 +0,0 @@
--/*
-- * Copyright 2016 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
-
--package io.netty.handler.ssl;
+- /**
+- * Converts the specified OpenSSL cipher suite to the Java cipher suite.
+- */
+- private String toJavaCipherSuite(String openSslCipherSuite) {
+- if (openSslCipherSuite == null) {
+- return null;
+- }
-
--import static org.junit.Assert.assertEquals;
--import static org.junit.Assert.assertTrue;
--import static org.junit.Assume.assumeFalse;
--import static org.junit.Assume.assumeTrue;
+- String version = SSL.getVersion(ssl);
+- String prefix = toJavaCipherSuitePrefix(version);
+- return CipherSuiteConverter.toJava(openSslCipherSuite, prefix);
+- }
-
--import java.io.ByteArrayOutputStream;
--import java.io.File;
--import java.io.FileInputStream;
+- /**
+- * Converts the protocol version string returned by {@link SSL#getVersion(long)} to protocol family string.
+- */
+- private static String toJavaCipherSuitePrefix(String protocolVersion) {
+- final char c;
+- if (protocolVersion == null || protocolVersion.isEmpty()) {
+- c = 0;
+- } else {
+- c = protocolVersion.charAt(0);
+- }
-
--import org.junit.Test;
+- switch (c) {
+- case 'T':
+- return "TLS";
+- case 'S':
+- return "SSL";
+- default:
+- return "UNKNOWN";
+- }
+- }
-
--import io.netty.handler.ssl.util.SelfSignedCertificate;
--import io.netty.util.ReferenceCountUtil;
+- @Override
+- public final void setUseClientMode(boolean clientMode) {
+- if (clientMode != this.clientMode) {
+- throw new UnsupportedOperationException();
+- }
+- }
-
--public class PemEncodedTest {
+- @Override
+- public final boolean getUseClientMode() {
+- return clientMode;
+- }
-
-- @Test
-- public void testPemEncodedOpenSsl() throws Exception {
-- testPemEncoded(SslProvider.OPENSSL);
+- @Override
+- public final void setNeedClientAuth(boolean b) {
+- setClientAuth(b ? ClientAuth.REQUIRE : ClientAuth.NONE);
- }
-
-- @Test
-- public void testPemEncodedOpenSslRef() throws Exception {
-- testPemEncoded(SslProvider.OPENSSL_REFCNT);
+- @Override
+- public final boolean getNeedClientAuth() {
+- return clientAuth == ClientAuth.REQUIRE;
- }
-
-- private static void testPemEncoded(SslProvider provider) throws Exception {
-- assumeTrue(OpenSsl.isAvailable());
-- assumeFalse(OpenSsl.useKeyManagerFactory());
-- PemPrivateKey pemKey;
-- PemX509Certificate pemCert;
-- SelfSignedCertificate ssc = new SelfSignedCertificate();
-- try {
-- pemKey = PemPrivateKey.valueOf(toByteArray(ssc.privateKey()));
-- pemCert = PemX509Certificate.valueOf(toByteArray(ssc.certificate()));
-- } finally {
-- ssc.delete();
-- }
+- @Override
+- public final void setWantClientAuth(boolean b) {
+- setClientAuth(b ? ClientAuth.OPTIONAL : ClientAuth.NONE);
+- }
-
-- SslContext context = SslContextBuilder.forServer(pemKey, pemCert)
-- .sslProvider(provider)
-- .build();
-- assertEquals(1, pemKey.refCnt());
-- assertEquals(1, pemCert.refCnt());
-- try {
-- assertTrue(context instanceof ReferenceCountedOpenSslContext);
-- } finally {
-- ReferenceCountUtil.release(context);
-- assertRelease(pemKey);
-- assertRelease(pemCert);
-- }
+- @Override
+- public final boolean getWantClientAuth() {
+- return clientAuth == ClientAuth.OPTIONAL;
- }
-
-- private static void assertRelease(PemEncoded encoded) {
-- assertTrue(encoded.release());
+- /**
+- * See <a href="https://www.openssl.org/docs/man1.0.2/ssl/SSL_set_verify.html">SSL_set_verify</a> and
+- * {@link SSL#setVerify(long, int, int)}.
+- */
+- @UnstableApi
+- public final synchronized void setVerify(int verifyMode, int depth) {
+- if (!isDestroyed()) {
+- SSL.setVerify(ssl, verifyMode, depth);
+- }
- }
-
-- private static byte[] toByteArray(File file) throws Exception {
-- FileInputStream in = new FileInputStream(file);
-- try {
-- ByteArrayOutputStream baos = new ByteArrayOutputStream();
-- try {
-- byte[] buf = new byte[1024];
-- int len;
-- while ((len = in.read(buf)) != -1) {
-- baos.write(buf, 0, len);
+- private void setClientAuth(ClientAuth mode) {
+- if (clientMode) {
+- return;
+- }
+- synchronized (this) {
+- if (clientAuth == mode) {
+- // No need to issue any JNI calls if the mode is the same
+- return;
+- }
+- if (!isDestroyed()) {
+- switch (mode) {
+- case NONE:
+- SSL.setVerify(ssl, SSL.SSL_CVERIFY_NONE, ReferenceCountedOpenSslContext.VERIFY_DEPTH);
+- break;
+- case REQUIRE:
+- SSL.setVerify(ssl, SSL.SSL_CVERIFY_REQUIRED, ReferenceCountedOpenSslContext.VERIFY_DEPTH);
+- break;
+- case OPTIONAL:
+- SSL.setVerify(ssl, SSL.SSL_CVERIFY_OPTIONAL, ReferenceCountedOpenSslContext.VERIFY_DEPTH);
+- break;
+- default:
+- throw new Error(mode.toString());
- }
-- } finally {
-- baos.close();
- }
+- clientAuth = mode;
+- }
+- }
-
-- return baos.toByteArray();
-- } finally {
-- in.close();
+- @Override
+- public final void setEnableSessionCreation(boolean b) {
+- if (b) {
+- throw new UnsupportedOperationException();
- }
- }
--}
-diff --git a/handler/src/test/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngineTest.java b/handler/src/test/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngineTest.java
-deleted file mode 100644
-index 6d38940..0000000
---- a/handler/src/test/java/io/netty/handler/ssl/ReferenceCountedOpenSslEngineTest.java
-+++ /dev/null
-@@ -1,57 +0,0 @@
--/*
-- * Copyright 2016 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
-
--import io.netty.util.ReferenceCountUtil;
+- @Override
+- public final boolean getEnableSessionCreation() {
+- return false;
+- }
-
--import javax.net.ssl.SSLEngine;
+- @SuppressJava6Requirement(reason = "Usage guarded by java version check")
+- @Override
+- public final synchronized SSLParameters getSSLParameters() {
+- SSLParameters sslParameters = super.getSSLParameters();
+-
+- int version = PlatformDependent.javaVersion();
+- if (version >= 7) {
+- sslParameters.setEndpointIdentificationAlgorithm(endPointIdentificationAlgorithm);
+- Java7SslParametersUtils.setAlgorithmConstraints(sslParameters, algorithmConstraints);
+- if (version >= 8) {
+- if (sniHostNames != null) {
+- Java8SslUtils.setSniHostNames(sslParameters, sniHostNames);
+- }
+- if (!isDestroyed()) {
+- Java8SslUtils.setUseCipherSuitesOrder(
+- sslParameters, (SSL.getOptions(ssl) & SSL.SSL_OP_CIPHER_SERVER_PREFERENCE) != 0);
+- }
+-
+- Java8SslUtils.setSNIMatchers(sslParameters, matchers);
+- }
+- }
+- return sslParameters;
+- }
-
--public class ReferenceCountedOpenSslEngineTest extends OpenSslEngineTest {
+- @SuppressJava6Requirement(reason = "Usage guarded by java version check")
+- @Override
+- public final synchronized void setSSLParameters(SSLParameters sslParameters) {
+- int version = PlatformDependent.javaVersion();
+- if (version >= 7) {
+- if (sslParameters.getAlgorithmConstraints() != null) {
+- throw new IllegalArgumentException("AlgorithmConstraints are not supported.");
+- }
-
-- public ReferenceCountedOpenSslEngineTest(BufferType type) {
-- super(type);
-- }
+- boolean isDestroyed = isDestroyed();
+- if (version >= 8) {
+- if (!isDestroyed) {
+- if (clientMode) {
+- final List<String> sniHostNames = Java8SslUtils.getSniHostNames(sslParameters);
+- for (String name: sniHostNames) {
+- SSL.setTlsExtHostName(ssl, name);
+- }
+- this.sniHostNames = sniHostNames;
+- }
+- if (Java8SslUtils.getUseCipherSuitesOrder(sslParameters)) {
+- SSL.setOptions(ssl, SSL.SSL_OP_CIPHER_SERVER_PREFERENCE);
+- } else {
+- SSL.clearOptions(ssl, SSL.SSL_OP_CIPHER_SERVER_PREFERENCE);
+- }
+- }
+- matchers = sslParameters.getSNIMatchers();
+- }
-
-- @Override
-- protected SslProvider sslClientProvider() {
-- return SslProvider.OPENSSL_REFCNT;
+- final String endPointIdentificationAlgorithm = sslParameters.getEndpointIdentificationAlgorithm();
+- if (!isDestroyed) {
+- // If the user asks for hostname verification we must ensure we verify the peer.
+- // If the user disables hostname verification we leave it up to the user to change the mode manually.
+- if (clientMode && isEndPointVerificationEnabled(endPointIdentificationAlgorithm)) {
+- SSL.setVerify(ssl, SSL.SSL_CVERIFY_REQUIRED, -1);
+- }
+- }
+- this.endPointIdentificationAlgorithm = endPointIdentificationAlgorithm;
+- algorithmConstraints = sslParameters.getAlgorithmConstraints();
+- }
+- super.setSSLParameters(sslParameters);
- }
-
-- @Override
-- protected SslProvider sslServerProvider() {
-- return SslProvider.OPENSSL_REFCNT;
+- private static boolean isEndPointVerificationEnabled(String endPointIdentificationAlgorithm) {
+- return endPointIdentificationAlgorithm != null && !endPointIdentificationAlgorithm.isEmpty();
- }
-
-- @Override
-- protected void cleanupClientSslContext(SslContext ctx) {
-- ReferenceCountUtil.release(ctx);
+- private boolean isDestroyed() {
+- return destroyed;
- }
-
-- @Override
-- protected void cleanupClientSslEngine(SSLEngine engine) {
-- ReferenceCountUtil.release(engine);
+- final boolean checkSniHostnameMatch(byte[] hostname) {
+- return Java8SslUtils.checkSniHostnameMatch(matchers, hostname);
- }
-
- @Override
-- protected void cleanupServerSslContext(SslContext ctx) {
-- ReferenceCountUtil.release(ctx);
+- public String getNegotiatedApplicationProtocol() {
+- return applicationProtocol;
- }
-
-- @Override
-- protected void cleanupServerSslEngine(SSLEngine engine) {
-- ReferenceCountUtil.release(engine);
+- private static long bufferAddress(ByteBuffer b) {
+- assert b.isDirect();
+- if (PlatformDependent.hasUnsafe()) {
+- return PlatformDependent.directBufferAddress(b);
+- }
+- return Buffer.address(b);
- }
--}
-diff --git a/handler/src/test/java/io/netty/handler/ssl/SniClientTest.java b/handler/src/test/java/io/netty/handler/ssl/SniClientTest.java
-deleted file mode 100644
-index 3193d20..0000000
---- a/handler/src/test/java/io/netty/handler/ssl/SniClientTest.java
-+++ /dev/null
-@@ -1,161 +0,0 @@
--/*
-- * Copyright 2016 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
--
--import io.netty.bootstrap.Bootstrap;
--import io.netty.bootstrap.ServerBootstrap;
--import io.netty.buffer.ByteBufAllocator;
--import io.netty.channel.Channel;
--import io.netty.channel.ChannelInitializer;
--import io.netty.channel.DefaultEventLoopGroup;
--import io.netty.channel.EventLoopGroup;
--import io.netty.channel.local.LocalAddress;
--import io.netty.channel.local.LocalChannel;
--import io.netty.channel.local.LocalServerChannel;
--import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
--import io.netty.handler.ssl.util.SelfSignedCertificate;
--import io.netty.util.Mapping;
--import io.netty.util.concurrent.Promise;
--import io.netty.util.internal.PlatformDependent;
--import org.junit.Assert;
--import org.junit.Assume;
--import org.junit.Test;
-
--import java.nio.channels.ClosedChannelException;
--
--public class SniClientTest {
--
-- @Test(timeout = 30000)
-- public void testSniClientJdkSslServerJdkSsl() throws Exception {
-- testSniClient(SslProvider.JDK, SslProvider.JDK);
-- }
+- private final class DefaultOpenSslSession implements OpenSslSession {
+- private final OpenSslSessionContext sessionContext;
-
-- @Test(timeout = 30000)
-- public void testSniClientOpenSslServerOpenSsl() throws Exception {
-- Assume.assumeTrue(OpenSsl.isAvailable());
-- testSniClient(SslProvider.OPENSSL, SslProvider.OPENSSL);
-- }
+- // These are guarded by synchronized(OpenSslEngine.this) as handshakeFinished() may be triggered by any
+- // thread.
+- private X509Certificate[] x509PeerCerts;
+- private Certificate[] peerCerts;
-
-- @Test(timeout = 30000)
-- public void testSniClientJdkSslServerOpenSsl() throws Exception {
-- Assume.assumeTrue(OpenSsl.isAvailable());
-- testSniClient(SslProvider.JDK, SslProvider.OPENSSL);
-- }
+- private String protocol;
+- private String cipher;
+- private byte[] id;
+- private long creationTime;
+- private volatile int applicationBufferSize = MAX_PLAINTEXT_LENGTH;
-
-- @Test(timeout = 30000)
-- public void testSniClientOpenSslServerJdkSsl() throws Exception {
-- Assume.assumeTrue(OpenSsl.isAvailable());
-- testSniClient(SslProvider.OPENSSL, SslProvider.JDK);
-- }
+- // lazy init for memory reasons
+- private Map<String, Object> values;
-
-- @Test(timeout = 30000)
-- public void testSniSNIMatcherMatchesClientJdkSslServerJdkSsl() throws Exception {
-- Assume.assumeTrue(PlatformDependent.javaVersion() >= 8);
-- SniClientJava8TestUtil.testSniClient(SslProvider.JDK, SslProvider.JDK, true);
-- }
+- DefaultOpenSslSession(OpenSslSessionContext sessionContext) {
+- this.sessionContext = sessionContext;
+- }
-
-- @Test(timeout = 30000, expected = ClosedChannelException.class)
-- public void testSniSNIMatcherDoesNotMatchClientJdkSslServerJdkSsl() throws Exception {
-- Assume.assumeTrue(PlatformDependent.javaVersion() >= 8);
-- SniClientJava8TestUtil.testSniClient(SslProvider.JDK, SslProvider.JDK, false);
-- }
+- private SSLSessionBindingEvent newSSLSessionBindingEvent(String name) {
+- return new SSLSessionBindingEvent(session, name);
+- }
-
-- @Test(timeout = 30000)
-- public void testSniSNIMatcherMatchesClientOpenSslServerOpenSsl() throws Exception {
-- Assume.assumeTrue(PlatformDependent.javaVersion() >= 8);
-- Assume.assumeTrue(OpenSsl.isAvailable());
-- SniClientJava8TestUtil.testSniClient(SslProvider.OPENSSL, SslProvider.OPENSSL, true);
-- }
+- @Override
+- public byte[] getId() {
+- synchronized (ReferenceCountedOpenSslEngine.this) {
+- if (id == null) {
+- return EmptyArrays.EMPTY_BYTES;
+- }
+- return id.clone();
+- }
+- }
-
-- @Test(timeout = 30000, expected = ClosedChannelException.class)
-- public void testSniSNIMatcherDoesNotMatchClientOpenSslServerOpenSsl() throws Exception {
-- Assume.assumeTrue(PlatformDependent.javaVersion() >= 8);
-- Assume.assumeTrue(OpenSsl.isAvailable());
-- SniClientJava8TestUtil.testSniClient(SslProvider.OPENSSL, SslProvider.OPENSSL, false);
-- }
+- @Override
+- public SSLSessionContext getSessionContext() {
+- return sessionContext;
+- }
-
-- @Test(timeout = 30000)
-- public void testSniSNIMatcherMatchesClientJdkSslServerOpenSsl() throws Exception {
-- Assume.assumeTrue(PlatformDependent.javaVersion() >= 8);
-- Assume.assumeTrue(OpenSsl.isAvailable());
-- SniClientJava8TestUtil.testSniClient(SslProvider.JDK, SslProvider.OPENSSL, true);
-- }
+- @Override
+- public long getCreationTime() {
+- synchronized (ReferenceCountedOpenSslEngine.this) {
+- if (creationTime == 0 && !isDestroyed()) {
+- creationTime = SSL.getTime(ssl) * 1000L;
+- }
+- }
+- return creationTime;
+- }
-
-- @Test(timeout = 30000, expected = ClosedChannelException.class)
-- public void testSniSNIMatcherDoesNotMatchClientJdkSslServerOpenSsl() throws Exception {
-- Assume.assumeTrue(PlatformDependent.javaVersion() >= 8);
-- Assume.assumeTrue(OpenSsl.isAvailable());
-- SniClientJava8TestUtil.testSniClient(SslProvider.JDK, SslProvider.OPENSSL, false);
-- }
+- @Override
+- public long getLastAccessedTime() {
+- long lastAccessed = ReferenceCountedOpenSslEngine.this.lastAccessed;
+- // if lastAccessed is -1 we will just return the creation time as the handshake was not started yet.
+- return lastAccessed == -1 ? getCreationTime() : lastAccessed;
+- }
-
-- @Test(timeout = 30000)
-- public void testSniSNIMatcherMatchesClientOpenSslServerJdkSsl() throws Exception {
-- Assume.assumeTrue(PlatformDependent.javaVersion() >= 8);
-- Assume.assumeTrue(OpenSsl.isAvailable());
-- SniClientJava8TestUtil.testSniClient(SslProvider.OPENSSL, SslProvider.JDK, true);
-- }
+- @Override
+- public void invalidate() {
+- synchronized (ReferenceCountedOpenSslEngine.this) {
+- if (!isDestroyed()) {
+- SSL.setTimeout(ssl, 0);
+- }
+- }
+- }
-
-- @Test(timeout = 30000, expected = ClosedChannelException.class)
-- public void testSniSNIMatcherDoesNotMatchClientOpenSslServerJdkSsl() throws Exception {
-- Assume.assumeTrue(PlatformDependent.javaVersion() >= 8);
-- Assume.assumeTrue(OpenSsl.isAvailable());
-- SniClientJava8TestUtil.testSniClient(SslProvider.OPENSSL, SslProvider.JDK, false);
-- }
+- @Override
+- public boolean isValid() {
+- synchronized (ReferenceCountedOpenSslEngine.this) {
+- if (!isDestroyed()) {
+- return System.currentTimeMillis() - (SSL.getTimeout(ssl) * 1000L) < (SSL.getTime(ssl) * 1000L);
+- }
+- }
+- return false;
+- }
-
-- private static void testSniClient(SslProvider sslClientProvider, SslProvider sslServerProvider) throws Exception {
-- final String sniHost = "sni.netty.io";
-- LocalAddress address = new LocalAddress("test");
-- EventLoopGroup group = new DefaultEventLoopGroup(1);
-- Channel sc = null;
-- Channel cc = null;
-- try {
-- SelfSignedCertificate cert = new SelfSignedCertificate();
-- final SslContext sslServerContext = SslContextBuilder.forServer(cert.key(), cert.cert())
-- .sslProvider(sslServerProvider).build();
+- @Override
+- public void putValue(String name, Object value) {
+- ObjectUtil.checkNotNull(name, "name");
+- ObjectUtil.checkNotNull(value, "value");
-
-- final Promise<String> promise = group.next().newPromise();
-- ServerBootstrap sb = new ServerBootstrap();
-- sc = sb.group(group).channel(LocalServerChannel.class).childHandler(new ChannelInitializer<Channel>() {
-- @Override
-- protected void initChannel(Channel ch) throws Exception {
-- ch.pipeline().addFirst(new SniHandler(new Mapping<String, SslContext>() {
-- @Override
-- public SslContext map(String input) {
-- promise.setSuccess(input);
-- return sslServerContext;
-- }
-- }));
+- final Object old;
+- synchronized (this) {
+- Map<String, Object> values = this.values;
+- if (values == null) {
+- // Use size of 2 to keep the memory overhead small
+- values = this.values = new HashMap<String, Object>(2);
- }
-- }).bind(address).syncUninterruptibly().channel();
--
-- SslContext sslContext = SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE)
-- .sslProvider(sslClientProvider).build();
-- Bootstrap cb = new Bootstrap();
-- cc = cb.group(group).channel(LocalChannel.class).handler(new SslHandler(
-- sslContext.newEngine(ByteBufAllocator.DEFAULT, sniHost, -1)))
-- .connect(address).syncUninterruptibly().channel();
-- Assert.assertEquals(sniHost, promise.syncUninterruptibly().getNow());
-- } finally {
-- if (cc != null) {
-- cc.close().syncUninterruptibly();
+- old = values.put(name, value);
- }
-- if (sc != null) {
-- sc.close().syncUninterruptibly();
+-
+- if (value instanceof SSLSessionBindingListener) {
+- // Use newSSLSessionBindingEvent so we alway use the wrapper if needed.
+- ((SSLSessionBindingListener) value).valueBound(newSSLSessionBindingEvent(name));
- }
-- group.shutdownGracefully();
+- notifyUnbound(old, name);
- }
-- }
--}
-diff --git a/handler/src/test/java/io/netty/handler/ssl/SniHandlerTest.java b/handler/src/test/java/io/netty/handler/ssl/SniHandlerTest.java
-deleted file mode 100644
-index 07c87c6..0000000
---- a/handler/src/test/java/io/netty/handler/ssl/SniHandlerTest.java
-+++ /dev/null
-@@ -1,496 +0,0 @@
--/*
-- * Copyright 2014 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
-
--package io.netty.handler.ssl;
+- @Override
+- public Object getValue(String name) {
+- ObjectUtil.checkNotNull(name, "name");
+- synchronized (this) {
+- if (values == null) {
+- return null;
+- }
+- return values.get(name);
+- }
+- }
-
--import static org.hamcrest.CoreMatchers.is;
--import static org.hamcrest.CoreMatchers.nullValue;
--import static org.junit.Assert.assertEquals;
--import static org.junit.Assert.assertThat;
--import static org.junit.Assert.assertTrue;
--import static org.junit.Assume.assumeTrue;
+- @Override
+- public void removeValue(String name) {
+- ObjectUtil.checkNotNull(name, "name");
-
--import java.io.File;
--import java.net.InetSocketAddress;
--import java.util.ArrayList;
--import java.util.List;
--import java.util.concurrent.CountDownLatch;
--import java.util.concurrent.TimeUnit;
+- final Object old;
+- synchronized (this) {
+- Map<String, Object> values = this.values;
+- if (values == null) {
+- return;
+- }
+- old = values.remove(name);
+- }
-
--import javax.net.ssl.SSLEngine;
+- notifyUnbound(old, name);
+- }
-
--import org.junit.Test;
+- @Override
+- public String[] getValueNames() {
+- synchronized (this) {
+- Map<String, Object> values = this.values;
+- if (values == null || values.isEmpty()) {
+- return EmptyArrays.EMPTY_STRINGS;
+- }
+- return values.keySet().toArray(new String[0]);
+- }
+- }
-
--import io.netty.bootstrap.Bootstrap;
--import io.netty.bootstrap.ServerBootstrap;
--import io.netty.buffer.ByteBufAllocator;
--import io.netty.buffer.Unpooled;
--import io.netty.channel.Channel;
--import io.netty.channel.ChannelFuture;
--import io.netty.channel.ChannelHandlerContext;
--import io.netty.channel.ChannelInitializer;
--import io.netty.channel.ChannelPipeline;
--import io.netty.channel.DefaultEventLoopGroup;
--import io.netty.channel.EventLoopGroup;
--import io.netty.channel.embedded.EmbeddedChannel;
--import io.netty.channel.local.LocalAddress;
--import io.netty.channel.local.LocalChannel;
--import io.netty.channel.local.LocalServerChannel;
--import io.netty.channel.nio.NioEventLoopGroup;
--import io.netty.channel.socket.nio.NioServerSocketChannel;
--import io.netty.channel.socket.nio.NioSocketChannel;
--import io.netty.handler.codec.DecoderException;
--import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
--import io.netty.handler.ssl.util.SelfSignedCertificate;
--import io.netty.util.DomainNameMapping;
--import io.netty.util.DomainNameMappingBuilder;
--import io.netty.util.Mapping;
--import io.netty.util.ReferenceCountUtil;
--import io.netty.util.ReferenceCounted;
--import io.netty.util.concurrent.Promise;
--import io.netty.util.internal.ObjectUtil;
--import io.netty.util.internal.StringUtil;
--import org.junit.runner.RunWith;
--import org.junit.runners.Parameterized;
+- private void notifyUnbound(Object value, String name) {
+- if (value instanceof SSLSessionBindingListener) {
+- // Use newSSLSessionBindingEvent so we alway use the wrapper if needed.
+- ((SSLSessionBindingListener) value).valueUnbound(newSSLSessionBindingEvent(name));
+- }
+- }
-
--(a)RunWith(Parameterized.class)
--public class SniHandlerTest {
+- /**
+- * Finish the handshake and so init everything in the {@link OpenSslSession} that should be accessible by
+- * the user.
+- */
+- @Override
+- public void handshakeFinished() throws SSLException {
+- synchronized (ReferenceCountedOpenSslEngine.this) {
+- if (!isDestroyed()) {
+- id = SSL.getSessionId(ssl);
+- cipher = toJavaCipherSuite(SSL.getCipherForSSL(ssl));
+- protocol = SSL.getVersion(ssl);
-
-- private static ApplicationProtocolConfig newApnConfig() {
-- return new ApplicationProtocolConfig(
-- ApplicationProtocolConfig.Protocol.ALPN,
-- // NO_ADVERTISE is currently the only mode supported by both OpenSsl and JDK providers.
-- ApplicationProtocolConfig.SelectorFailureBehavior.NO_ADVERTISE,
-- // ACCEPT is currently the only mode supported by both OpenSsl and JDK providers.
-- ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT,
-- "myprotocol");
-- }
+- initPeerCerts();
+- selectApplicationProtocol();
+- calculateMaxWrapOverhead();
-
-- private static void assumeApnSupported(SslProvider provider) {
-- switch (provider) {
-- case OPENSSL:
-- case OPENSSL_REFCNT:
-- assumeTrue(OpenSsl.isAlpnSupported());
-- break;
-- case JDK:
-- assumeTrue(JettyAlpnSslEngine.isAvailable());
-- break;
-- default:
-- throw new Error();
+- handshakeState = HandshakeState.FINISHED;
+- } else {
+- throw new SSLException("Already closed");
+- }
+- }
- }
-- }
-
-- private static SslContext makeSslContext(SslProvider provider, boolean apn) throws Exception {
-- if (apn) {
-- assumeApnSupported(provider);
+- /**
+- * Init peer certificates that can be obtained via {@link #getPeerCertificateChain()}
+- * and {@link #getPeerCertificates()}.
+- */
+- private void initPeerCerts() {
+- // Return the full chain from the JNI layer.
+- byte[][] chain = SSL.getPeerCertChain(ssl);
+- if (clientMode) {
+- if (isEmpty(chain)) {
+- peerCerts = EmptyArrays.EMPTY_CERTIFICATES;
+- x509PeerCerts = EmptyArrays.EMPTY_JAVAX_X509_CERTIFICATES;
+- } else {
+- peerCerts = new Certificate[chain.length];
+- x509PeerCerts = new X509Certificate[chain.length];
+- initCerts(chain, 0);
+- }
+- } else {
+- // if used on the server side SSL_get_peer_cert_chain(...) will not include the remote peer
+- // certificate. We use SSL_get_peer_certificate to get it in this case and add it to our
+- // array later.
+- //
+- // See https://www.openssl.org/docs/ssl/SSL_get_peer_cert_chain.html
+- byte[] clientCert = SSL.getPeerCertificate(ssl);
+- if (isEmpty(clientCert)) {
+- peerCerts = EmptyArrays.EMPTY_CERTIFICATES;
+- x509PeerCerts = EmptyArrays.EMPTY_JAVAX_X509_CERTIFICATES;
+- } else {
+- if (isEmpty(chain)) {
+- peerCerts = new Certificate[] {new OpenSslX509Certificate(clientCert)};
+- x509PeerCerts = new X509Certificate[] {new OpenSslJavaxX509Certificate(clientCert)};
+- } else {
+- peerCerts = new Certificate[chain.length + 1];
+- x509PeerCerts = new X509Certificate[chain.length + 1];
+- peerCerts[0] = new OpenSslX509Certificate(clientCert);
+- x509PeerCerts[0] = new OpenSslJavaxX509Certificate(clientCert);
+- initCerts(chain, 1);
+- }
+- }
+- }
- }
-
-- File keyFile = new File(SniHandlerTest.class.getResource("test_encrypted.pem").getFile());
-- File crtFile = new File(SniHandlerTest.class.getResource("test.crt").getFile());
--
-- SslContextBuilder sslCtxBuilder = SslContextBuilder.forServer(crtFile, keyFile, "12345")
-- .sslProvider(provider);
-- if (apn) {
-- sslCtxBuilder.applicationProtocolConfig(newApnConfig());
+- private void initCerts(byte[][] chain, int startPos) {
+- for (int i = 0; i < chain.length; i++) {
+- int certPos = startPos + i;
+- peerCerts[certPos] = new OpenSslX509Certificate(chain[i]);
+- x509PeerCerts[certPos] = new OpenSslJavaxX509Certificate(chain[i]);
+- }
- }
-- return sslCtxBuilder.build();
-- }
-
-- private static SslContext makeSslClientContext(SslProvider provider, boolean apn) throws Exception {
-- if (apn) {
-- assumeApnSupported(provider);
+- /**
+- * Select the application protocol used.
+- */
+- private void selectApplicationProtocol() throws SSLException {
+- ApplicationProtocolConfig.SelectedListenerFailureBehavior behavior = apn.selectedListenerFailureBehavior();
+- List<String> protocols = apn.protocols();
+- String applicationProtocol;
+- switch (apn.protocol()) {
+- case NONE:
+- break;
+- // We always need to check for applicationProtocol == null as the remote peer may not support
+- // the TLS extension or may have returned an empty selection.
+- case ALPN:
+- applicationProtocol = SSL.getAlpnSelected(ssl);
+- if (applicationProtocol != null) {
+- ReferenceCountedOpenSslEngine.this.applicationProtocol = selectApplicationProtocol(
+- protocols, behavior, applicationProtocol);
+- }
+- break;
+- case NPN:
+- applicationProtocol = SSL.getNextProtoNegotiated(ssl);
+- if (applicationProtocol != null) {
+- ReferenceCountedOpenSslEngine.this.applicationProtocol = selectApplicationProtocol(
+- protocols, behavior, applicationProtocol);
+- }
+- break;
+- case NPN_AND_ALPN:
+- applicationProtocol = SSL.getAlpnSelected(ssl);
+- if (applicationProtocol == null) {
+- applicationProtocol = SSL.getNextProtoNegotiated(ssl);
+- }
+- if (applicationProtocol != null) {
+- ReferenceCountedOpenSslEngine.this.applicationProtocol = selectApplicationProtocol(
+- protocols, behavior, applicationProtocol);
+- }
+- break;
+- default:
+- throw new Error();
+- }
- }
-
-- File crtFile = new File(SniHandlerTest.class.getResource("test.crt").getFile());
--
-- SslContextBuilder sslCtxBuilder = SslContextBuilder.forClient().trustManager(crtFile).sslProvider(provider);
-- if (apn) {
-- sslCtxBuilder.applicationProtocolConfig(newApnConfig());
+- private String selectApplicationProtocol(List<String> protocols,
+- ApplicationProtocolConfig.SelectedListenerFailureBehavior behavior,
+- String applicationProtocol) throws SSLException {
+- if (behavior == ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT) {
+- return applicationProtocol;
+- } else {
+- int size = protocols.size();
+- assert size > 0;
+- if (protocols.contains(applicationProtocol)) {
+- return applicationProtocol;
+- } else {
+- if (behavior == ApplicationProtocolConfig.SelectedListenerFailureBehavior.CHOOSE_MY_LAST_PROTOCOL) {
+- return protocols.get(size - 1);
+- } else {
+- throw new SSLException("unknown protocol " + applicationProtocol);
+- }
+- }
+- }
- }
-- return sslCtxBuilder.build();
-- }
-
-- @Parameterized.Parameters(name = "{index}: sslProvider={0}")
-- public static Iterable<?> data() {
-- List<SslProvider> params = new ArrayList<SslProvider>(3);
-- if (OpenSsl.isAvailable()) {
-- params.add(SslProvider.OPENSSL);
-- params.add(SslProvider.OPENSSL_REFCNT);
+- @Override
+- public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException {
+- synchronized (ReferenceCountedOpenSslEngine.this) {
+- if (isEmpty(peerCerts)) {
+- throw new SSLPeerUnverifiedException("peer not verified");
+- }
+- return peerCerts.clone();
+- }
- }
-- params.add(SslProvider.JDK);
-- return params;
-- }
--
-- private final SslProvider provider;
-
-- public SniHandlerTest(SslProvider provider) {
-- this.provider = provider;
-- }
--
-- @Test
-- public void testServerNameParsing() throws Exception {
-- SslContext nettyContext = makeSslContext(provider, false);
-- SslContext leanContext = makeSslContext(provider, false);
-- SslContext leanContext2 = makeSslContext(provider, false);
--
-- try {
-- DomainNameMapping<SslContext> mapping = new DomainNameMappingBuilder<SslContext>(nettyContext)
-- .add("*.netty.io", nettyContext)
-- // input with custom cases
-- .add("*.LEANCLOUD.CN", leanContext)
-- // a hostname conflict with previous one, since we are using order-sensitive config,
-- // the engine won't be used with the handler.
-- .add("chat4.leancloud.cn", leanContext2)
-- .build();
--
-- SniHandler handler = new SniHandler(mapping);
-- EmbeddedChannel ch = new EmbeddedChannel(handler);
--
-- try {
-- // hex dump of a client hello packet, which contains hostname "CHAT4.LEANCLOUD.CN"
-- String tlsHandshakeMessageHex1 = "16030100";
-- // part 2
-- String tlsHandshakeMessageHex = "c6010000c20303bb0855d66532c05a0ef784f7c384feeafa68b3" +
-- "b655ac7288650d5eed4aa3fb52000038c02cc030009fcca9cca8ccaac02b" +
-- "c02f009ec024c028006bc023c0270067c00ac0140039c009c0130033009d" +
-- "009c003d003c0035002f00ff010000610000001700150000124348415434" +
-- "2e4c45414e434c4f55442e434e000b000403000102000a000a0008001d00" +
-- "170019001800230000000d0020001e060106020603050105020503040104" +
-- "0204030301030203030201020202030016000000170000";
--
-- ch.writeInbound(Unpooled.wrappedBuffer(StringUtil.decodeHexDump(tlsHandshakeMessageHex1)));
-- ch.writeInbound(Unpooled.wrappedBuffer(StringUtil.decodeHexDump(tlsHandshakeMessageHex)));
--
-- // This should produce an alert
-- assertTrue(ch.finish());
--
-- assertThat(handler.hostname(), is("chat4.leancloud.cn"));
-- assertThat(handler.sslContext(), is(leanContext));
-- } finally {
-- ch.finishAndReleaseAll();
+- @Override
+- public Certificate[] getLocalCertificates() {
+- Certificate[] localCerts = ReferenceCountedOpenSslEngine.this.localCertificateChain;
+- if (localCerts == null) {
+- return null;
- }
-- } finally {
-- releaseAll(leanContext, leanContext2, nettyContext);
+- return localCerts.clone();
- }
-- }
--
-- @Test(expected = DecoderException.class)
-- public void testNonAsciiServerNameParsing() throws Exception {
-- SslContext nettyContext = makeSslContext(provider, false);
-- SslContext leanContext = makeSslContext(provider, false);
-- SslContext leanContext2 = makeSslContext(provider, false);
-
-- try {
-- DomainNameMapping<SslContext> mapping = new DomainNameMappingBuilder<SslContext>(nettyContext)
-- .add("*.netty.io", nettyContext)
-- // input with custom cases
-- .add("*.LEANCLOUD.CN", leanContext)
-- // a hostname conflict with previous one, since we are using order-sensitive config,
-- // the engine won't be used with the handler.
-- .add("chat4.leancloud.cn", leanContext2)
-- .build();
--
-- SniHandler handler = new SniHandler(mapping);
-- EmbeddedChannel ch = new EmbeddedChannel(handler);
--
-- try {
-- // hex dump of a client hello packet, which contains an invalid hostname "CHAT4。LEANCLOUD。CN"
-- String tlsHandshakeMessageHex1 = "16030100";
-- // part 2
-- String tlsHandshakeMessageHex = "bd010000b90303a74225676d1814ba57faff3b366" +
-- "3656ed05ee9dbb2a4dbb1bb1c32d2ea5fc39e0000000100008c0000001700150000164348" +
-- "415434E380824C45414E434C4F5544E38082434E000b000403000102000a00340032000e0" +
-- "00d0019000b000c00180009000a0016001700080006000700140015000400050012001300" +
-- "0100020003000f0010001100230000000d0020001e0601060206030501050205030401040" +
-- "20403030103020303020102020203000f00010133740000";
--
-- // Push the handshake message.
-- // Decode should fail because of the badly encoded "HostName" string in the SNI extension
-- // that isn't ASCII as per RFC 6066 - https://tools.ietf.org/html/rfc6066#page-6
-- ch.writeInbound(Unpooled.wrappedBuffer(StringUtil.decodeHexDump(tlsHandshakeMessageHex1)));
-- ch.writeInbound(Unpooled.wrappedBuffer(StringUtil.decodeHexDump(tlsHandshakeMessageHex)));
-- } finally {
-- ch.finishAndReleaseAll();
+- @Override
+- public X509Certificate[] getPeerCertificateChain() throws SSLPeerUnverifiedException {
+- synchronized (ReferenceCountedOpenSslEngine.this) {
+- if (isEmpty(x509PeerCerts)) {
+- throw new SSLPeerUnverifiedException("peer not verified");
+- }
+- return x509PeerCerts.clone();
- }
-- } finally {
-- releaseAll(leanContext, leanContext2, nettyContext);
- }
-- }
--
-- @Test
-- public void testFallbackToDefaultContext() throws Exception {
-- SslContext nettyContext = makeSslContext(provider, false);
-- SslContext leanContext = makeSslContext(provider, false);
-- SslContext leanContext2 = makeSslContext(provider, false);
--
-- try {
-- DomainNameMapping<SslContext> mapping = new DomainNameMappingBuilder<SslContext>(nettyContext)
-- .add("*.netty.io", nettyContext)
-- // input with custom cases
-- .add("*.LEANCLOUD.CN", leanContext)
-- // a hostname conflict with previous one, since we are using order-sensitive config,
-- // the engine won't be used with the handler.
-- .add("chat4.leancloud.cn", leanContext2)
-- .build();
-
-- SniHandler handler = new SniHandler(mapping);
-- EmbeddedChannel ch = new EmbeddedChannel(handler);
--
-- // invalid
-- byte[] message = {22, 3, 1, 0, 0};
+- @Override
+- public Principal getPeerPrincipal() throws SSLPeerUnverifiedException {
+- Certificate[] peer = getPeerCertificates();
+- // No need for null or length > 0 is needed as this is done in getPeerCertificates()
+- // already.
+- return ((java.security.cert.X509Certificate) peer[0]).getSubjectX500Principal();
+- }
-
-- try {
-- // Push the handshake message.
-- ch.writeInbound(Unpooled.wrappedBuffer(message));
-- } catch (Exception e) {
-- // expected
+- @Override
+- public Principal getLocalPrincipal() {
+- Certificate[] local = ReferenceCountedOpenSslEngine.this.localCertificateChain;
+- if (local == null || local.length == 0) {
+- return null;
- }
--
-- assertThat(ch.finish(), is(false));
-- assertThat(handler.hostname(), nullValue());
-- assertThat(handler.sslContext(), is(nettyContext));
-- } finally {
-- releaseAll(leanContext, leanContext2, nettyContext);
+- return ((java.security.cert.X509Certificate) local[0]).getIssuerX500Principal();
- }
-- }
--
-- @Test
-- public void testSniWithApnHandler() throws Exception {
-- SslContext nettyContext = makeSslContext(provider, true);
-- SslContext sniContext = makeSslContext(provider, true);
-- final SslContext clientContext = makeSslClientContext(provider, true);
-- try {
-- final CountDownLatch serverApnDoneLatch = new CountDownLatch(1);
-- final CountDownLatch clientApnDoneLatch = new CountDownLatch(1);
--
-- final DomainNameMapping<SslContext> mapping = new DomainNameMappingBuilder<SslContext>(nettyContext)
-- .add("*.netty.io", nettyContext)
-- .add("sni.fake.site", sniContext).build();
-- final SniHandler handler = new SniHandler(mapping);
-- EventLoopGroup group = new NioEventLoopGroup(2);
-- Channel serverChannel = null;
-- Channel clientChannel = null;
-- try {
-- ServerBootstrap sb = new ServerBootstrap();
-- sb.group(group);
-- sb.channel(NioServerSocketChannel.class);
-- sb.childHandler(new ChannelInitializer<Channel>() {
-- @Override
-- protected void initChannel(Channel ch) throws Exception {
-- ChannelPipeline p = ch.pipeline();
-- // Server side SNI.
-- p.addLast(handler);
-- // Catch the notification event that APN has completed successfully.
-- p.addLast(new ApplicationProtocolNegotiationHandler("foo") {
-- @Override
-- protected void configurePipeline(ChannelHandlerContext ctx, String protocol) {
-- serverApnDoneLatch.countDown();
-- }
-- });
-- }
-- });
--
-- Bootstrap cb = new Bootstrap();
-- cb.group(group);
-- cb.channel(NioSocketChannel.class);
-- cb.handler(new ChannelInitializer<Channel>() {
-- @Override
-- protected void initChannel(Channel ch) throws Exception {
-- ch.pipeline().addLast(new SslHandler(clientContext.newEngine(
-- ch.alloc(), "sni.fake.site", -1)));
-- // Catch the notification event that APN has completed successfully.
-- ch.pipeline().addLast(new ApplicationProtocolNegotiationHandler("foo") {
-- @Override
-- protected void configurePipeline(ChannelHandlerContext ctx, String protocol) {
-- clientApnDoneLatch.countDown();
-- }
-- });
-- }
-- });
--
-- serverChannel = sb.bind(new InetSocketAddress(0)).sync().channel();
-
-- ChannelFuture ccf = cb.connect(serverChannel.localAddress());
-- assertTrue(ccf.awaitUninterruptibly().isSuccess());
-- clientChannel = ccf.channel();
--
-- assertTrue(serverApnDoneLatch.await(5, TimeUnit.SECONDS));
-- assertTrue(clientApnDoneLatch.await(5, TimeUnit.SECONDS));
-- assertThat(handler.hostname(), is("sni.fake.site"));
-- assertThat(handler.sslContext(), is(sniContext));
-- } finally {
-- if (serverChannel != null) {
-- serverChannel.close().sync();
-- }
-- if (clientChannel != null) {
-- clientChannel.close().sync();
+- @Override
+- public String getCipherSuite() {
+- synchronized (ReferenceCountedOpenSslEngine.this) {
+- if (cipher == null) {
+- return SslUtils.INVALID_CIPHER;
- }
-- group.shutdownGracefully(0, 0, TimeUnit.MICROSECONDS);
+- return cipher;
- }
-- } finally {
-- releaseAll(clientContext, nettyContext, sniContext);
- }
-- }
--
-- @Test(timeout = 30000)
-- public void testReplaceHandler() throws Exception {
-- switch (provider) {
-- case OPENSSL:
-- case OPENSSL_REFCNT:
-- final String sniHost = "sni.netty.io";
-- LocalAddress address = new LocalAddress("testReplaceHandler-" + Math.random());
-- EventLoopGroup group = new DefaultEventLoopGroup(1);
-- Channel sc = null;
-- Channel cc = null;
-- SslContext sslContext = null;
--
-- SelfSignedCertificate cert = new SelfSignedCertificate();
--
-- try {
-- final SslContext sslServerContext = SslContextBuilder
-- .forServer(cert.key(), cert.cert())
-- .sslProvider(provider)
-- .build();
--
-- final Mapping<String, SslContext> mapping = new Mapping<String, SslContext>() {
-- @Override
-- public SslContext map(String input) {
-- return sslServerContext;
-- }
-- };
--
-- final Promise<Void> releasePromise = group.next().newPromise();
--
-- final SniHandler handler = new SniHandler(mapping) {
-- @Override
-- protected void replaceHandler(ChannelHandlerContext ctx,
-- String hostname, final SslContext sslContext)
-- throws Exception {
--
-- boolean success = false;
-- try {
-- // The SniHandler's replaceHandler() method allows us to implement custom behavior.
-- // As an example, we want to release() the SslContext upon channelInactive() or rather
-- // when the SslHandler closes it's SslEngine. If you take a close look at SslHandler
-- // you'll see that it's doing it in the #handlerRemoved0() method.
--
-- SSLEngine sslEngine = sslContext.newEngine(ctx.alloc());
-- try {
-- SslHandler customSslHandler = new CustomSslHandler(sslContext, sslEngine) {
-- @Override
-- public void handlerRemoved0(ChannelHandlerContext ctx) throws Exception {
-- try {
-- super.handlerRemoved0(ctx);
-- } finally {
-- releasePromise.trySuccess(null);
-- }
-- }
-- };
-- ctx.pipeline().replace(this, CustomSslHandler.class.getName(), customSslHandler);
-- success = true;
-- } finally {
-- if (!success) {
-- ReferenceCountUtil.safeRelease(sslEngine);
-- }
-- }
-- } finally {
-- if (!success) {
-- ReferenceCountUtil.safeRelease(sslContext);
-- releasePromise.cancel(true);
-- }
-- }
-- }
-- };
--
-- ServerBootstrap sb = new ServerBootstrap();
-- sc = sb.group(group).channel(LocalServerChannel.class)
-- .childHandler(new ChannelInitializer<Channel>() {
-- @Override
-- protected void initChannel(Channel ch) throws Exception {
-- ch.pipeline().addFirst(handler);
-- }
-- }).bind(address).syncUninterruptibly().channel();
--
-- sslContext = SslContextBuilder.forClient().sslProvider(provider)
-- .trustManager(InsecureTrustManagerFactory.INSTANCE).build();
--
-- Bootstrap cb = new Bootstrap();
-- cc = cb.group(group).channel(LocalChannel.class).handler(new SslHandler(
-- sslContext.newEngine(ByteBufAllocator.DEFAULT, sniHost, -1)))
-- .connect(address).syncUninterruptibly().channel();
--
-- cc.writeAndFlush(Unpooled.wrappedBuffer("Hello, World!".getBytes()))
-- .syncUninterruptibly();
--
-- // Notice how the server's SslContext refCnt is 1
-- assertEquals(1, ((ReferenceCounted) sslServerContext).refCnt());
--
-- // The client disconnects
-- cc.close().syncUninterruptibly();
-- if (!releasePromise.awaitUninterruptibly(10L, TimeUnit.SECONDS)) {
-- throw new IllegalStateException("It doesn't seem #replaceHandler() got called.");
-- }
-
-- // We should have successfully release() the SslContext
-- assertEquals(0, ((ReferenceCounted) sslServerContext).refCnt());
-- } finally {
-- if (cc != null) {
-- cc.close().syncUninterruptibly();
-- }
-- if (sc != null) {
-- sc.close().syncUninterruptibly();
-- }
-- if (sslContext != null) {
-- ReferenceCountUtil.release(sslContext);
+- @Override
+- public String getProtocol() {
+- String protocol = this.protocol;
+- if (protocol == null) {
+- synchronized (ReferenceCountedOpenSslEngine.this) {
+- if (!isDestroyed()) {
+- protocol = SSL.getVersion(ssl);
+- } else {
+- protocol = StringUtil.EMPTY_STRING;
- }
-- group.shutdownGracefully();
--
-- cert.delete();
- }
-- case JDK:
-- return;
-- default:
-- throw new Error();
+- }
+- return protocol;
- }
-- }
--
-- /**
-- * This is a {@link SslHandler} that will call {@code release()} on the {@link SslContext} when
-- * the client disconnects.
-- *
-- * @see SniHandlerTest#testReplaceHandler()
-- */
-- private static class CustomSslHandler extends SslHandler {
-- private final SslContext sslContext;
-
-- public CustomSslHandler(SslContext sslContext, SSLEngine sslEngine) {
-- super(sslEngine);
-- this.sslContext = ObjectUtil.checkNotNull(sslContext, "sslContext");
+- @Override
+- public String getPeerHost() {
+- return ReferenceCountedOpenSslEngine.this.getPeerHost();
- }
-
- @Override
-- public void handlerRemoved0(ChannelHandlerContext ctx) throws Exception {
-- super.handlerRemoved0(ctx);
-- ReferenceCountUtil.release(sslContext);
+- public int getPeerPort() {
+- return ReferenceCountedOpenSslEngine.this.getPeerPort();
- }
-- }
-
-- private static void releaseAll(SslContext... contexts) {
-- for (SslContext ctx: contexts) {
-- ReferenceCountUtil.release(ctx);
+- @Override
+- public int getPacketBufferSize() {
+- return maxEncryptedPacketLength();
- }
-- }
--}
-diff --git a/handler/src/test/java/io/netty/handler/ssl/SslContextBuilderTest.java b/handler/src/test/java/io/netty/handler/ssl/SslContextBuilderTest.java
-deleted file mode 100644
-index 752424c..0000000
---- a/handler/src/test/java/io/netty/handler/ssl/SslContextBuilderTest.java
-+++ /dev/null
-@@ -1,132 +0,0 @@
--/*
-- * Copyright 2015 The Netty Project
-- *
-- * The Netty Project licenses this file to you under the Apache License,
-- * version 2.0 (the "License"); you may not use this file except in compliance
-- * with the License. You may obtain a copy of the License at:
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- * License for the specific language governing permissions and limitations
-- * under the License.
-- */
--package io.netty.handler.ssl;
--
--import static org.junit.Assert.assertFalse;
--import static org.junit.Assert.assertTrue;
-
--import io.netty.buffer.UnpooledByteBufAllocator;
--import io.netty.handler.ssl.util.SelfSignedCertificate;
--import org.junit.Assume;
--import org.junit.Test;
--
--import javax.net.ssl.SSLEngine;
+- @Override
+- public int getApplicationBufferSize() {
+- return applicationBufferSize;
+- }
-
--public class SslContextBuilderTest {
--
-- @Test
-- public void testClientContextFromFileJdk() throws Exception {
-- testClientContextFromFile(SslProvider.JDK);
-- }
--
-- @Test
-- public void testClientContextFromFileOpenssl() throws Exception {
-- Assume.assumeTrue(OpenSsl.isAvailable());
-- testClientContextFromFile(SslProvider.OPENSSL);
-- }
--
-- @Test
-- public void testClientContextJdk() throws Exception {
-- testClientContext(SslProvider.JDK);
-- }
--
-- @Test
-- public void testClientContextOpenssl() throws Exception {
-- Assume.assumeTrue(OpenSsl.isAvailable());
-- testClientContext(SslProvider.OPENSSL);
-- }
--
-- @Test
-- public void testServerContextFromFileJdk() throws Exception {
-- testServerContextFromFile(SslProvider.JDK);
-- }
--
-- @Test
-- public void testServerContextFromFileOpenssl() throws Exception {
-- Assume.assumeTrue(OpenSsl.isAvailable());
-- testServerContextFromFile(SslProvider.OPENSSL);
-- }
--
-- @Test
-- public void testServerContextJdk() throws Exception {
-- testServerContext(SslProvider.JDK);
-- }
--
-- @Test
-- public void testServerContextOpenssl() throws Exception {
-- Assume.assumeTrue(OpenSsl.isAvailable());
-- testServerContext(SslProvider.OPENSSL);
-- }
--
-- private static void testClientContextFromFile(SslProvider provider) throws Exception {
-- SelfSignedCertificate cert = new SelfSignedCertificate();
-- SslContextBuilder builder = SslContextBuilder.forClient()
-- .sslProvider(provider)
-- .keyManager(cert.certificate(),
-- cert.privateKey())
-- .trustManager(cert.certificate())
-- .clientAuth(ClientAuth.OPTIONAL);
-- SslContext context = builder.build();
-- SSLEngine engine = context.newEngine(UnpooledByteBufAllocator.DEFAULT);
-- assertFalse(engine.getWantClientAuth());
-- assertFalse(engine.getNeedClientAuth());
-- engine.closeInbound();
-- engine.closeOutbound();
-- }
--
-- private static void testClientContext(SslProvider provider) throws Exception {
-- SelfSignedCertificate cert = new SelfSignedCertificate();
-- SslContextBuilder builder = SslContextBuilder.forClient()
-- .sslProvider(provider)
-- .keyManager(cert.key(), cert.cert())
-- .trustManager(cert.cert())
-- .clientAuth(ClientAuth.OPTIONAL);
-- SslContext context = builder.build();
-- SSLEngine engine = context.newEngine(UnpooledByteBufAllocator.DEFAULT);
-- assertFalse(engine.getWantClientAuth());
-- assertFalse(engine.getNeedClientAuth());
-- engine.closeInbound();
-- engine.closeOutbound();
-- }
--
-- private static void testServerContextFromFile(SslProvider provider) throws Exception {
-- SelfSignedCertificate cert = new SelfSignedCertificate();
-- SslContextBuilder builder = SslContextBuilder.forServer(cert.certificate(), cert.privateKey())
-- .sslProvider(provider)
-- .trustManager(cert.certificate())
-- .clientAuth(ClientAuth.OPTIONAL);
-- SslContext context = builder.build();
-- SSLEngine engine = context.newEngine(UnpooledByteBufAllocator.DEFAULT);
-- assertTrue(engine.getWantClientAuth());
-- assertFalse(engine.getNeedClientAuth());
-- engine.closeInbound();
-- engine.closeOutbound();
-- }
--
-- private static void testServerContext(SslProvider provider) throws Exception {
-- SelfSignedCertificate cert = new SelfSignedCertificate();
-- SslContextBuilder builder = SslContextBuilder.forServer(cert.key(), cert.cert())
-- .sslProvider(provider)
-- .trustManager(cert.cert())
-- .clientAuth(ClientAuth.REQUIRE);
-- SslContext context = builder.build();
-- SSLEngine engine = context.newEngine(UnpooledByteBufAllocator.DEFAULT);
-- assertFalse(engine.getWantClientAuth());
-- assertTrue(engine.getNeedClientAuth());
-- engine.closeInbound();
-- engine.closeOutbound();
+- @Override
+- public void tryExpandApplicationBufferSize(int packetLengthDataOnly) {
+- if (packetLengthDataOnly > MAX_PLAINTEXT_LENGTH && applicationBufferSize != MAX_RECORD_SIZE) {
+- applicationBufferSize = MAX_RECORD_SIZE;
+- }
+- }
- }
-}
-diff --git a/handler/src/test/java/io/netty/handler/ssl/SslErrorTest.java b/handler/src/test/java/io/netty/handler/ssl/SslErrorTest.java
+diff --git a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslServerContext.java b/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslServerContext.java
deleted file mode 100644
-index aacdb69..0000000
---- a/handler/src/test/java/io/netty/handler/ssl/SslErrorTest.java
+index bac027a3b4..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/ReferenceCountedOpenSslServerContext.java
+++ /dev/null
-@@ -1,255 +0,0 @@
+@@ -1,286 +0,0 @@
-/*
- * Copyright 2016 The Netty Project
- *
@@ -8134,351 +8008,449 @@ index aacdb69..0000000
- */
-package io.netty.handler.ssl;
-
--import io.netty.bootstrap.Bootstrap;
--import io.netty.bootstrap.ServerBootstrap;
--import io.netty.channel.Channel;
--import io.netty.channel.ChannelHandlerContext;
--import io.netty.channel.ChannelInboundHandlerAdapter;
--import io.netty.channel.ChannelInitializer;
--import io.netty.channel.EventLoopGroup;
--import io.netty.channel.nio.NioEventLoopGroup;
--import io.netty.channel.socket.nio.NioServerSocketChannel;
--import io.netty.channel.socket.nio.NioSocketChannel;
--import io.netty.handler.logging.LogLevel;
--import io.netty.handler.logging.LoggingHandler;
--import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
--import io.netty.handler.ssl.util.SelfSignedCertificate;
--import io.netty.handler.ssl.util.SimpleTrustManagerFactory;
--import io.netty.util.ReferenceCountUtil;
--import io.netty.util.concurrent.Promise;
--import io.netty.util.internal.EmptyArrays;
--import org.junit.Assume;
--import org.junit.Test;
--import org.junit.runner.RunWith;
--import org.junit.runners.Parameterized;
+-import io.netty.buffer.ByteBufAllocator;
+-import io.netty.internal.tcnative.CertificateCallback;
+-import io.netty.internal.tcnative.SSL;
+-import io.netty.internal.tcnative.SSLContext;
+-import io.netty.internal.tcnative.SniHostNameMatcher;
+-import io.netty.util.CharsetUtil;
+-import io.netty.util.internal.PlatformDependent;
+-import io.netty.util.internal.SuppressJava6Requirement;
+-import io.netty.util.internal.SystemPropertyUtil;
+-import io.netty.util.internal.logging.InternalLogger;
+-import io.netty.util.internal.logging.InternalLoggerFactory;
-
--import javax.net.ssl.ManagerFactoryParameters;
--import javax.net.ssl.SSLException;
--import javax.net.ssl.TrustManager;
--import javax.net.ssl.X509TrustManager;
--import javax.security.auth.x500.X500Principal;
--import java.io.File;
-import java.security.KeyStore;
--import java.security.cert.CRLReason;
--import java.security.cert.CertPathValidatorException;
--import java.security.cert.CertificateException;
--import java.security.cert.CertificateExpiredException;
--import java.security.cert.CertificateNotYetValidException;
--import java.security.cert.CertificateRevokedException;
--import java.security.cert.Extension;
+-import java.security.PrivateKey;
-import java.security.cert.X509Certificate;
--import java.util.ArrayList;
--import java.util.Collection;
--import java.util.Collections;
--import java.util.Date;
--import java.util.List;
--import java.util.Locale;
+-import javax.net.ssl.KeyManagerFactory;
+-import javax.net.ssl.SSLException;
+-import javax.net.ssl.TrustManagerFactory;
+-import javax.net.ssl.X509ExtendedTrustManager;
+-import javax.net.ssl.X509TrustManager;
-
+-import static io.netty.util.internal.ObjectUtil.checkNotNull;
-
--(a)RunWith(Parameterized.class)
--public class SslErrorTest {
+-/**
+- * A server-side {@link SslContext} which uses OpenSSL's SSL/TLS implementation.
+- * <p>Instances of this class must be {@link #release() released} or else native memory will leak!
+- *
+- * <p>Instances of this class <strong>must not</strong> be released before any {@link ReferenceCountedOpenSslEngine}
+- * which depends upon the instance of this class is released. Otherwise if any method of
+- * {@link ReferenceCountedOpenSslEngine} is called which uses this class's JNI resources the JVM may crash.
+- */
+-public final class ReferenceCountedOpenSslServerContext extends ReferenceCountedOpenSslContext {
+- private static final InternalLogger logger =
+- InternalLoggerFactory.getInstance(ReferenceCountedOpenSslServerContext.class);
+- private static final byte[] ID = {'n', 'e', 't', 't', 'y'};
+- private final OpenSslServerSessionContext sessionContext;
-
-- @Parameterized.Parameters(name = "{index}: serverProvider = {0}, clientProvider = {1}, exception = {2}")
-- public static Collection<Object[]> data() {
-- List<SslProvider> serverProviders = new ArrayList<SslProvider>(2);
-- List<SslProvider> clientProviders = new ArrayList<SslProvider>(3);
+- private static final boolean ENABLE_SESSION_TICKET =
+- SystemPropertyUtil.getBoolean("jdk.tls.server.enableSessionTicketExtension", false);
-
-- if (OpenSsl.isAvailable()) {
-- serverProviders.add(SslProvider.OPENSSL);
-- serverProviders.add(SslProvider.OPENSSL_REFCNT);
-- clientProviders.add(SslProvider.OPENSSL);
-- clientProviders.add(SslProvider.OPENSSL_REFCNT);
-- }
-- // We not test with SslProvider.JDK on the server side as the JDK implementation currently just send the same
-- // alert all the time, sigh.....
-- clientProviders.add(SslProvider.JDK);
--
-- List<CertificateException> exceptions = new ArrayList<CertificateException>(6);
-- exceptions.add(new CertificateExpiredException());
-- exceptions.add(new CertificateNotYetValidException());
-- exceptions.add(new CertificateRevokedException(
-- new Date(), CRLReason.AA_COMPROMISE, new X500Principal(""),
-- Collections.<String, Extension>emptyMap()));
--
-- // Also use wrapped exceptions as this is what the JDK implementation of X509TrustManagerFactory is doing.
-- exceptions.add(newCertificateException(CertPathValidatorException.BasicReason.EXPIRED));
-- exceptions.add(newCertificateException(CertPathValidatorException.BasicReason.NOT_YET_VALID));
-- exceptions.add(newCertificateException(CertPathValidatorException.BasicReason.REVOKED));
--
-- List<Object[]> params = new ArrayList<Object[]>();
-- for (SslProvider serverProvider: serverProviders) {
-- for (SslProvider clientProvider: clientProviders) {
-- for (CertificateException exception: exceptions) {
-- params.add(new Object[] { serverProvider, clientProvider, exception});
-- }
+- ReferenceCountedOpenSslServerContext(
+- X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory,
+- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory,
+- Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
+- long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[] protocols, boolean startTls,
+- boolean enableOcsp, String keyStore) throws SSLException {
+- this(trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory, ciphers,
+- cipherFilter, toNegotiator(apn), sessionCacheSize, sessionTimeout, clientAuth, protocols, startTls,
+- enableOcsp, keyStore);
+- }
+-
+- ReferenceCountedOpenSslServerContext(
+- X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory,
+- X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory,
+- Iterable<String> ciphers, CipherSuiteFilter cipherFilter, OpenSslApplicationProtocolNegotiator apn,
+- long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[] protocols, boolean startTls,
+- boolean enableOcsp, String keyStore) throws SSLException {
+- super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, SSL.SSL_MODE_SERVER, keyCertChain,
+- clientAuth, protocols, startTls, enableOcsp, true);
+- // Create a new SSL_CTX and configure it.
+- boolean success = false;
+- try {
+- sessionContext = newSessionContext(this, ctx, engineMap, trustCertCollection, trustManagerFactory,
+- keyCertChain, key, keyPassword, keyManagerFactory, keyStore);
+- if (ENABLE_SESSION_TICKET) {
+- sessionContext.setTicketKeys();
+- }
+- success = true;
+- } finally {
+- if (!success) {
+- release();
- }
- }
-- return params;
- }
-
-- private static CertificateException newCertificateException(CertPathValidatorException.Reason reason) {
-- return new TestCertificateException(
-- new CertPathValidatorException("x", null, null, -1, reason));
+- @Override
+- public OpenSslServerSessionContext sessionContext() {
+- return sessionContext;
- }
-
-- private final SslProvider serverProvider;
-- private final SslProvider clientProvider;
-- private final CertificateException exception;
+- static OpenSslServerSessionContext newSessionContext(ReferenceCountedOpenSslContext thiz, long ctx,
+- OpenSslEngineMap engineMap,
+- X509Certificate[] trustCertCollection,
+- TrustManagerFactory trustManagerFactory,
+- X509Certificate[] keyCertChain, PrivateKey key,
+- String keyPassword, KeyManagerFactory keyManagerFactory,
+- String keyStore)
+- throws SSLException {
+- OpenSslKeyMaterialProvider keyMaterialProvider = null;
+- try {
+- try {
+- SSLContext.setVerify(ctx, SSL.SSL_CVERIFY_NONE, VERIFY_DEPTH);
+- if (!OpenSsl.useKeyManagerFactory()) {
+- if (keyManagerFactory != null) {
+- throw new IllegalArgumentException(
+- "KeyManagerFactory not supported");
+- }
+- checkNotNull(keyCertChain, "keyCertChain");
-
-- public SslErrorTest(SslProvider serverProvider, SslProvider clientProvider, CertificateException exception) {
-- this.serverProvider = serverProvider;
-- this.clientProvider = clientProvider;
-- this.exception = exception;
-- }
+- setKeyMaterial(ctx, keyCertChain, key, keyPassword);
+- } else {
+- // javadocs state that keyManagerFactory has precedent over keyCertChain, and we must have a
+- // keyManagerFactory for the server so build one if it is not specified.
+- if (keyManagerFactory == null) {
+- char[] keyPasswordChars = keyStorePassword(keyPassword);
+- KeyStore ks = buildKeyStore(keyCertChain, key, keyPasswordChars, keyStore);
+- if (ks.aliases().hasMoreElements()) {
+- keyManagerFactory = new OpenSslX509KeyManagerFactory();
+- } else {
+- keyManagerFactory = new OpenSslCachingX509KeyManagerFactory(
+- KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()));
+- }
+- keyManagerFactory.init(ks, keyPasswordChars);
+- }
+- keyMaterialProvider = providerFor(keyManagerFactory, keyPassword);
-
-- @Test(timeout = 30000)
-- public void testCorrectAlert() throws Exception {
-- // As this only works correctly at the moment when OpenSslEngine is used on the server-side there is
-- // no need to run it if there is no openssl is available at all.
-- Assume.assumeTrue(OpenSsl.isAvailable());
+- SSLContext.setCertificateCallback(ctx, new OpenSslServerCertificateCallback(
+- engineMap, new OpenSslKeyMaterialManager(keyMaterialProvider)));
+- }
+- } catch (Exception e) {
+- throw new SSLException("failed to set certificate and key", e);
+- }
+- try {
+- if (trustCertCollection != null) {
+- trustManagerFactory = buildTrustManagerFactory(trustCertCollection, trustManagerFactory, keyStore);
+- } else if (trustManagerFactory == null) {
+- // Mimic the way SSLContext.getInstance(KeyManager[], null, null) works
+- trustManagerFactory = TrustManagerFactory.getInstance(
+- TrustManagerFactory.getDefaultAlgorithm());
+- trustManagerFactory.init((KeyStore) null);
+- }
-
-- SelfSignedCertificate ssc = new SelfSignedCertificate();
-- final SslContext sslServerCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey())
-- .sslProvider(serverProvider)
-- .trustManager(new SimpleTrustManagerFactory() {
-- @Override
-- protected void engineInit(KeyStore keyStore) { }
-- @Override
-- protected void engineInit(ManagerFactoryParameters managerFactoryParameters) { }
+- final X509TrustManager manager = chooseTrustManager(trustManagerFactory.getTrustManagers());
-
-- @Override
-- protected TrustManager[] engineGetTrustManagers() {
-- return new TrustManager[] { new X509TrustManager() {
+- // IMPORTANT: The callbacks set for verification must be static to prevent memory leak as
+- // otherwise the context can never be collected. This is because the JNI code holds
+- // a global reference to the callbacks.
+- //
+- // See https://github.com/netty/netty/issues/5372
-
-- @Override
-- public void checkClientTrusted(X509Certificate[] x509Certificates, String s)
-- throws CertificateException {
-- throw exception;
-- }
+- setVerifyCallback(ctx, engineMap, manager);
-
-- @Override
-- public void checkServerTrusted(X509Certificate[] x509Certificates, String s)
-- throws CertificateException {
-- // NOOP
+- X509Certificate[] issuers = manager.getAcceptedIssuers();
+- if (issuers != null && issuers.length > 0) {
+- long bio = 0;
+- try {
+- bio = toBIO(ByteBufAllocator.DEFAULT, issuers);
+- if (!SSLContext.setCACertificateBio(ctx, bio)) {
+- throw new SSLException("unable to setup accepted issuers for trustmanager " + manager);
+- }
+- } finally {
+- freeBio(bio);
- }
+- }
-
-- @Override
-- public X509Certificate[] getAcceptedIssuers() {
-- return EmptyArrays.EMPTY_X509_CERTIFICATES;
-- }
-- } };
+- if (PlatformDependent.javaVersion() >= 8) {
+- // Only do on Java8+ as SNIMatcher is not supported in earlier releases.
+- // IMPORTANT: The callbacks set for hostname matching must be static to prevent memory leak as
+- // otherwise the context can never be collected. This is because the JNI code holds
+- // a global reference to the matcher.
+- SSLContext.setSniHostnameMatcher(ctx, new OpenSslSniHostnameMatcher(engineMap));
+- }
+- } catch (SSLException e) {
+- throw e;
+- } catch (Exception e) {
+- throw new SSLException("unable to setup trustmanager", e);
- }
-- }).clientAuth(ClientAuth.REQUIRE).build();
-
-- final SslContext sslClientCtx = SslContextBuilder.forClient()
-- .trustManager(InsecureTrustManagerFactory.INSTANCE)
-- .keyManager(new File(getClass().getResource("test.crt").getFile()),
-- new File(getClass().getResource("test_unencrypted.pem").getFile()))
-- .sslProvider(clientProvider).build();
+- OpenSslServerSessionContext sessionContext = new OpenSslServerSessionContext(thiz, keyMaterialProvider);
+- sessionContext.setSessionIdContext(ID);
-
-- Channel serverChannel = null;
-- Channel clientChannel = null;
-- EventLoopGroup group = new NioEventLoopGroup();
-- try {
-- serverChannel = new ServerBootstrap().group(group)
-- .channel(NioServerSocketChannel.class)
-- .handler(new LoggingHandler(LogLevel.INFO))
-- .childHandler(new ChannelInitializer<Channel>() {
-- @Override
-- protected void initChannel(Channel ch) throws Exception {
-- ch.pipeline().addLast(sslServerCtx.newHandler(ch.alloc()));
-- ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {
--
-- @Override
-- public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
-- ctx.close();
-- }
-- });
-- }
-- }).bind(0).sync().channel();
--
-- final Promise<Void> promise = group.next().newPromise();
--
-- clientChannel = new Bootstrap().group(group)
-- .channel(NioSocketChannel.class)
-- .handler(new ChannelInitializer<Channel>() {
-- @Override
-- protected void initChannel(Channel ch) throws Exception {
-- ch.pipeline().addLast(sslClientCtx.newHandler(ch.alloc()));
-- ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {
-- @Override
-- public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
-- // Unwrap as its wrapped by a DecoderException
-- Throwable unwrappedCause = cause.getCause();
-- if (unwrappedCause instanceof SSLException) {
-- if (exception instanceof TestCertificateException) {
-- CertPathValidatorException.Reason reason =
-- ((CertPathValidatorException) exception.getCause()).getReason();
-- if (reason == CertPathValidatorException.BasicReason.EXPIRED) {
-- verifyException(unwrappedCause, "expired", promise);
-- } else if (reason == CertPathValidatorException.BasicReason.NOT_YET_VALID) {
-- verifyException(unwrappedCause, "bad", promise);
-- } else if (reason == CertPathValidatorException.BasicReason.REVOKED) {
-- verifyException(unwrappedCause, "revoked", promise);
-- }
-- } else if (exception instanceof CertificateExpiredException) {
-- verifyException(unwrappedCause, "expired", promise);
-- } else if (exception instanceof CertificateNotYetValidException) {
-- verifyException(unwrappedCause, "bad", promise);
-- } else if (exception instanceof CertificateRevokedException) {
-- verifyException(unwrappedCause, "revoked", promise);
-- }
-- }
-- }
-- });
-- }
-- }).connect(serverChannel.localAddress()).syncUninterruptibly().channel();
-- // Block until we received the correct exception
-- promise.syncUninterruptibly();
+- keyMaterialProvider = null;
+-
+- return sessionContext;
- } finally {
-- if (clientChannel != null) {
-- clientChannel.close().syncUninterruptibly();
-- }
-- if (serverChannel != null) {
-- serverChannel.close().syncUninterruptibly();
+- if (keyMaterialProvider != null) {
+- keyMaterialProvider.destroy();
- }
-- group.shutdownGracefully();
--
-- ReferenceCountUtil.release(sslServerCtx);
-- ReferenceCountUtil.release(sslClientCtx);
- }
- }
-
-- // Its a bit hacky to verify against the message that is part of the exception but there is no other way
-- // at the moment as there are no different exceptions for the different alerts.
-- private static void verifyException(Throwable cause, String messagePart, Promise<Void> promise) {
-- String message = cause.getMessage();
-- if (message.toLowerCase(Locale.UK).contains(messagePart.toLowerCase(Locale.UK))) {
-- promise.setSuccess(null);
+- @SuppressJava6Requirement(reason = "Guarded by java version check")
+- private static void setVerifyCallback(long ctx, OpenSslEngineMap engineMap, X509TrustManager manager) {
+- // Use this to prevent an error when running on java < 7
+- if (useExtendedTrustManager(manager)) {
+- SSLContext.setCertVerifyCallback(ctx, new ExtendedTrustManagerVerifyCallback(
+- engineMap, (X509ExtendedTrustManager) manager));
- } else {
-- promise.setFailure(new AssertionError("message not contains '" + messagePart + "': " + message));
+- SSLContext.setCertVerifyCallback(ctx, new TrustManagerVerifyCallback(engineMap, manager));
- }
- }
-
-- private static final class TestCertificateException extends CertificateException {
+- private static final class OpenSslServerCertificateCallback implements CertificateCallback {
+- private final OpenSslEngineMap engineMap;
+- private final OpenSslKeyMaterialManager keyManagerHolder;
-
-- public TestCertificateException(Throwable cause) {
-- super(cause);
+- OpenSslServerCertificateCallback(OpenSslEngineMap engineMap, OpenSslKeyMaterialManager keyManagerHolder) {
+- this.engineMap = engineMap;
+- this.keyManagerHolder = keyManagerHolder;
- }
-- }
--}
-diff --git a/handler/src/test/java/io/netty/handler/ssl/SslHandlerTest.java b/handler/src/test/java/io/netty/handler/ssl/SslHandlerTest.java
-index 5ef43de..52c4d22 100644
---- a/handler/src/test/java/io/netty/handler/ssl/SslHandlerTest.java
-+++ b/handler/src/test/java/io/netty/handler/ssl/SslHandlerTest.java
-@@ -121,35 +121,6 @@ public class SslHandlerTest {
- }
- }
-
-- @Test
-- public void testReleaseSslEngine() throws Exception {
-- assumeTrue(OpenSsl.isAvailable());
-
-- SelfSignedCertificate cert = new SelfSignedCertificate();
-- try {
-- SslContext sslContext = SslContextBuilder.forServer(cert.certificate(), cert.privateKey())
-- .sslProvider(SslProvider.OPENSSL)
-- .build();
+- @Override
+- public void handle(long ssl, byte[] keyTypeBytes, byte[][] asn1DerEncodedPrincipals) throws Exception {
+- final ReferenceCountedOpenSslEngine engine = engineMap.get(ssl);
+- if (engine == null) {
+- // Maybe null if destroyed in the meantime.
+- return;
+- }
- try {
-- SSLEngine sslEngine = sslContext.newEngine(ByteBufAllocator.DEFAULT);
-- EmbeddedChannel ch = new EmbeddedChannel(new SslHandler(sslEngine));
+- // For now we just ignore the asn1DerEncodedPrincipals as this is kind of inline with what the
+- // OpenJDK SSLEngineImpl does.
+- keyManagerHolder.setKeyMaterialServerSide(engine);
+- } catch (Throwable cause) {
+- logger.debug("Failed to set the server-side key material", cause);
+- engine.initHandshakeException(cause);
+- }
+- }
+- }
-
-- assertEquals(1, ((ReferenceCounted) sslContext).refCnt());
-- assertEquals(1, ((ReferenceCounted) sslEngine).refCnt());
+- private static final class TrustManagerVerifyCallback extends AbstractCertificateVerifier {
+- private final X509TrustManager manager;
-
-- assertTrue(ch.finishAndReleaseAll());
-- ch.close().syncUninterruptibly();
+- TrustManagerVerifyCallback(OpenSslEngineMap engineMap, X509TrustManager manager) {
+- super(engineMap);
+- this.manager = manager;
+- }
-
-- assertEquals(1, ((ReferenceCounted) sslContext).refCnt());
-- assertEquals(0, ((ReferenceCounted) sslEngine).refCnt());
-- } finally {
-- ReferenceCountUtil.release(sslContext);
-- }
-- } finally {
-- cert.delete();
+- @Override
+- void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts, String auth)
+- throws Exception {
+- manager.checkClientTrusted(peerCerts, auth);
- }
- }
-
- private static final class TlsReadTest extends ChannelOutboundHandlerAdapter {
- private volatile boolean readIssued;
-
-@@ -279,13 +250,6 @@ public class SslHandlerTest {
- testAlertProducedAndSend(SslProvider.JDK);
- }
-
-- @Test(timeout = 30000)
-- public void testAlertProducedAndSendOpenSsl() throws Exception {
-- assumeTrue(OpenSsl.isAvailable());
-- testAlertProducedAndSend(SslProvider.OPENSSL);
-- testAlertProducedAndSend(SslProvider.OPENSSL_REFCNT);
+- @SuppressJava6Requirement(reason = "Usage guarded by java version check")
+- private static final class ExtendedTrustManagerVerifyCallback extends AbstractCertificateVerifier {
+- private final X509ExtendedTrustManager manager;
+-
+- ExtendedTrustManagerVerifyCallback(OpenSslEngineMap engineMap, X509ExtendedTrustManager manager) {
+- super(engineMap);
+- this.manager = OpenSslTlsv13X509ExtendedTrustManager.wrap(manager);
+- }
+-
+- @Override
+- void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts, String auth)
+- throws Exception {
+- manager.checkClientTrusted(peerCerts, auth, engine);
+- }
- }
-
- private void testAlertProducedAndSend(SslProvider provider) throws Exception {
- SelfSignedCertificate ssc = new SelfSignedCertificate();
-
-@@ -425,12 +389,6 @@ public class SslHandlerTest {
- testCloseNotify(SslProvider.JDK, 5000, false);
- }
-
-- @Test(timeout = 30000)
-- public void testCloseNotifyReceivedOpenSsl() throws Exception {
-- assumeTrue(OpenSsl.isAvailable());
-- testCloseNotify(SslProvider.OPENSSL, 5000, false);
-- testCloseNotify(SslProvider.OPENSSL_REFCNT, 5000, false);
+- private static final class OpenSslSniHostnameMatcher implements SniHostNameMatcher {
+- private final OpenSslEngineMap engineMap;
+-
+- OpenSslSniHostnameMatcher(OpenSslEngineMap engineMap) {
+- this.engineMap = engineMap;
+- }
+-
+- @Override
+- public boolean match(long ssl, String hostname) {
+- ReferenceCountedOpenSslEngine engine = engineMap.get(ssl);
+- if (engine != null) {
+- // TODO: In the next release of tcnative we should pass the byte[] directly in and not use a String.
+- return engine.checkSniHostnameMatch(hostname.getBytes(CharsetUtil.UTF_8));
+- }
+- logger.warn("No ReferenceCountedOpenSslEngine found for SSL pointer: {}", ssl);
+- return false;
+- }
- }
+-}
+diff --git a/handler/src/main/java/io/netty/handler/ssl/SslContext.java b/handler/src/main/java/io/netty/handler/ssl/SslContext.java
+index fef2702cfb..eb5110d145 100644
+--- a/handler/src/main/java/io/netty/handler/ssl/SslContext.java
++++ b/handler/src/main/java/io/netty/handler/ssl/SslContext.java
+@@ -120,11 +120,7 @@ public abstract class SslContext {
+ }
- @Test(timeout = 30000)
- public void testCloseNotifyReceivedJdkTimeout() throws Exception {
-@@ -438,24 +396,10 @@ public class SslHandlerTest {
+ private static SslProvider defaultProvider() {
+- if (OpenSsl.isAvailable()) {
+- return SslProvider.OPENSSL;
+- } else {
+- return SslProvider.JDK;
+- }
++ return SslProvider.JDK;
}
- @Test(timeout = 30000)
-- public void testCloseNotifyReceivedOpenSslTimeout() throws Exception {
-- assumeTrue(OpenSsl.isAvailable());
-- testCloseNotify(SslProvider.OPENSSL, 100, true);
-- testCloseNotify(SslProvider.OPENSSL_REFCNT, 100, true);
-- }
+ /**
+@@ -466,18 +462,6 @@ public abstract class SslContext {
+ trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword,
+ keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout,
+ clientAuth, protocols, startTls, keyStoreType);
+- case OPENSSL:
+- verifyNullSslContextProvider(provider, sslContextProvider);
+- return new OpenSslServerContext(
+- trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword,
+- keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout,
+- clientAuth, protocols, startTls, enableOcsp, keyStoreType);
+- case OPENSSL_REFCNT:
+- verifyNullSslContextProvider(provider, sslContextProvider);
+- return new ReferenceCountedOpenSslServerContext(
+- trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword,
+- keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout,
+- clientAuth, protocols, startTls, enableOcsp, keyStoreType);
+ default:
+ throw new Error(provider.toString());
+ }
+@@ -822,18 +806,6 @@ public abstract class SslContext {
+ trustCert, trustManagerFactory, keyCertChain, key, keyPassword,
+ keyManagerFactory, ciphers, cipherFilter, apn, protocols, sessionCacheSize,
+ sessionTimeout, keyStoreType);
+- case OPENSSL:
+- verifyNullSslContextProvider(provider, sslContextProvider);
+- return new OpenSslClientContext(
+- trustCert, trustManagerFactory, keyCertChain, key, keyPassword,
+- keyManagerFactory, ciphers, cipherFilter, apn, protocols, sessionCacheSize, sessionTimeout,
+- enableOcsp, keyStoreType);
+- case OPENSSL_REFCNT:
+- verifyNullSslContextProvider(provider, sslContextProvider);
+- return new ReferenceCountedOpenSslClientContext(
+- trustCert, trustManagerFactory, keyCertChain, key, keyPassword,
+- keyManagerFactory, ciphers, cipherFilter, apn, protocols, sessionCacheSize, sessionTimeout,
+- enableOcsp, keyStoreType);
+ default:
+ throw new Error(provider.toString());
+ }
+diff --git a/handler/src/main/java/io/netty/handler/ssl/SslHandler.java b/handler/src/main/java/io/netty/handler/ssl/SslHandler.java
+index 8e11bbf4cc..56be212b09 100644
+--- a/handler/src/main/java/io/netty/handler/ssl/SslHandler.java
++++ b/handler/src/main/java/io/netty/handler/ssl/SslHandler.java
+@@ -181,53 +181,6 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
+ private static final int MAX_PLAINTEXT_LENGTH = 16 * 1024;
+
+ private enum SslEngineType {
+- TCNATIVE(true, COMPOSITE_CUMULATOR) {
+- @Override
+- SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int len, ByteBuf out)
+- throws SSLException {
+- int nioBufferCount = in.nioBufferCount();
+- int writerIndex = out.writerIndex();
+- final SSLEngineResult result;
+- if (nioBufferCount > 1) {
+- /*
+- * If {@link OpenSslEngine} is in use,
+- * we can use a special {@link OpenSslEngine#unwrap(ByteBuffer[], ByteBuffer[])} method
+- * that accepts multiple {@link ByteBuffer}s without additional memory copies.
+- */
+- ReferenceCountedOpenSslEngine opensslEngine = (ReferenceCountedOpenSslEngine) handler.engine;
+- try {
+- handler.singleBuffer[0] = toByteBuffer(out, writerIndex,
+- out.writableBytes());
+- result = opensslEngine.unwrap(in.nioBuffers(readerIndex, len), handler.singleBuffer);
+- } finally {
+- handler.singleBuffer[0] = null;
+- }
+- } else {
+- result = handler.engine.unwrap(toByteBuffer(in, readerIndex, len),
+- toByteBuffer(out, writerIndex, out.writableBytes()));
+- }
+- out.writerIndex(writerIndex + result.bytesProduced());
+- return result;
+- }
-
-- @Test(timeout = 30000)
- public void testCloseNotifyNotWaitForResponseJdk() throws Exception {
- testCloseNotify(SslProvider.JDK, 0, false);
- }
+- @Override
+- ByteBuf allocateWrapBuffer(SslHandler handler, ByteBufAllocator allocator,
+- int pendingBytes, int numComponents) {
+- return allocator.directBuffer(((ReferenceCountedOpenSslEngine) handler.engine)
+- .calculateMaxLengthForWrap(pendingBytes, numComponents));
+- }
+-
+- @Override
+- int calculatePendingData(SslHandler handler, int guess) {
+- int sslPending = ((ReferenceCountedOpenSslEngine) handler.engine).sslPending();
+- return sslPending > 0 ? sslPending : guess;
+- }
+-
+- @Override
+- boolean jdkCompatibilityMode(SSLEngine engine) {
+- return ((ReferenceCountedOpenSslEngine) engine).jdkCompatibilityMode;
+- }
+- },
+ JDK(false, MERGE_CUMULATOR) {
+ @Override
+ SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int len, ByteBuf out)
+@@ -280,7 +233,7 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
+ };
+
+ static SslEngineType forEngine(SSLEngine engine) {
+- return engine instanceof ReferenceCountedOpenSslEngine ? TCNATIVE : JDK;
++ return JDK;
+ }
+
+ SslEngineType(boolean wantsDirectBuffer, Cumulator cumulator) {
+diff --git a/handler/src/main/java/io/netty/handler/ssl/SslMasterKeyHandler.java b/handler/src/main/java/io/netty/handler/ssl/SslMasterKeyHandler.java
+index b1c710c841..44ef0456ed 100644
+--- a/handler/src/main/java/io/netty/handler/ssl/SslMasterKeyHandler.java
++++ b/handler/src/main/java/io/netty/handler/ssl/SslMasterKeyHandler.java
+@@ -138,9 +138,6 @@ public abstract class SslMasterKeyHandler extends ChannelInboundHandlerAdapter {
+ "via reflection.", e);
+ }
+ accept(secretKey, sslSession);
+- } else if (OpenSsl.isAvailable() && engine instanceof ReferenceCountedOpenSslEngine) {
+- SecretKeySpec secretKey = ((ReferenceCountedOpenSslEngine) engine).masterKey();
+- accept(secretKey, sslSession);
+ }
+ }
+ }
+diff --git a/handler/src/main/java/io/netty/handler/ssl/SslProvider.java b/handler/src/main/java/io/netty/handler/ssl/SslProvider.java
+index e72cfed8d9..5263314e7c 100644
+--- a/handler/src/main/java/io/netty/handler/ssl/SslProvider.java
++++ b/handler/src/main/java/io/netty/handler/ssl/SslProvider.java
+@@ -26,16 +26,7 @@ public enum SslProvider {
+ /**
+ * JDK's default implementation.
+ */
+- JDK,
+- /**
+- * OpenSSL-based implementation.
+- */
+- OPENSSL,
+- /**
+- * OpenSSL-based implementation which does not have finalizers and instead implements {@link ReferenceCounted}.
+- */
+- @UnstableApi
+- OPENSSL_REFCNT;
++ JDK;
-- @Test(timeout = 30000)
-- public void testCloseNotifyNotWaitForResponseOpenSsl() throws Exception {
-- assumeTrue(OpenSsl.isAvailable());
-- testCloseNotify(SslProvider.OPENSSL, 0, false);
-- testCloseNotify(SslProvider.OPENSSL_REFCNT, 0, false);
-- }
--
- private static void testCloseNotify(SslProvider provider, final long closeNotifyReadTimeout, final boolean timeout)
- throws Exception {
- SelfSignedCertificate ssc = new SelfSignedCertificate();
-@@ -720,7 +664,7 @@ public class SslHandlerTest {
+ /**
+ * Returns {@code true} if the specified {@link SslProvider} supports
+@@ -45,9 +36,6 @@ public enum SslProvider {
switch (provider) {
- case OPENSSL:
- case OPENSSL_REFCNT:
-- return OpenSsl.isAvailable();
-+ return false;
+ case JDK:
+ return JdkAlpnApplicationProtocolNegotiator.isAlpnSupported();
+- case OPENSSL:
+- case OPENSSL_REFCNT:
+- return OpenSsl.isAlpnSupported();
default:
- return true;
+ throw new Error("Unknown SslProvider: " + provider);
}
-diff --git a/handler/src/test/java/io/netty/handler/ssl/ocsp/OcspTest.java b/handler/src/test/java/io/netty/handler/ssl/ocsp/OcspTest.java
+diff --git a/handler/src/main/java/io/netty/handler/ssl/ocsp/OcspClientHandler.java b/handler/src/main/java/io/netty/handler/ssl/ocsp/OcspClientHandler.java
deleted file mode 100644
-index 4aecc74..0000000
---- a/handler/src/test/java/io/netty/handler/ssl/ocsp/OcspTest.java
+index c45c50e1e3..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/ocsp/OcspClientHandler.java
+++ /dev/null
-@@ -1,501 +0,0 @@
+@@ -1,61 +0,0 @@
-/*
- * Copyright 2017 The Netty Project
- *
@@ -8494,492 +8466,102 @@ index 4aecc74..0000000
- * License for the specific language governing permissions and limitations
- * under the License.
- */
--
-package io.netty.handler.ssl.ocsp;
-
--import io.netty.bootstrap.Bootstrap;
--import io.netty.bootstrap.ServerBootstrap;
--import io.netty.buffer.ByteBufAllocator;
--import io.netty.buffer.Unpooled;
--import io.netty.channel.Channel;
--import io.netty.channel.ChannelHandler;
-import io.netty.channel.ChannelHandlerContext;
-import io.netty.channel.ChannelInboundHandlerAdapter;
--import io.netty.channel.ChannelInitializer;
--import io.netty.channel.ChannelPipeline;
--import io.netty.channel.DefaultEventLoopGroup;
--import io.netty.channel.EventLoopGroup;
--import io.netty.channel.local.LocalAddress;
--import io.netty.channel.local.LocalChannel;
--import io.netty.channel.local.LocalServerChannel;
--import io.netty.handler.ssl.OpenSsl;
+-import io.netty.handler.ssl.ReferenceCountedOpenSslContext;
-import io.netty.handler.ssl.ReferenceCountedOpenSslEngine;
--import io.netty.handler.ssl.SslContext;
--import io.netty.handler.ssl.SslContextBuilder;
--import io.netty.handler.ssl.SslHandler;
--import io.netty.handler.ssl.SslProvider;
--import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
--import io.netty.handler.ssl.util.SelfSignedCertificate;
--import io.netty.util.CharsetUtil;
--import io.netty.util.ReferenceCountUtil;
--
--import java.net.SocketAddress;
--import java.util.concurrent.CountDownLatch;
--import java.util.concurrent.TimeUnit;
--import java.util.concurrent.TimeoutException;
--import java.util.concurrent.atomic.AtomicReference;
+-import io.netty.handler.ssl.SslHandshakeCompletionEvent;
+-import io.netty.util.internal.ObjectUtil;
+-import io.netty.util.internal.UnstableApi;
-
-import javax.net.ssl.SSLHandshakeException;
-
--import org.junit.BeforeClass;
--import org.junit.Test;
--
--import static org.junit.Assert.assertArrayEquals;
--import static org.junit.Assert.assertNotNull;
--import static org.junit.Assert.assertNotSame;
--import static org.junit.Assert.assertNull;
--import static org.junit.Assert.assertSame;
--import static org.junit.Assert.assertTrue;
--import static org.junit.Assume.assumeTrue;
--
--public class OcspTest {
--
-- @BeforeClass
-- public static void checkOcspSupported() {
-- assumeTrue(OpenSsl.isOcspSupported());
-- }
--
-- @Test(expected = IllegalArgumentException.class)
-- public void testJdkClientEnableOcsp() throws Exception {
-- SslContextBuilder.forClient()
-- .sslProvider(SslProvider.JDK)
-- .enableOcsp(true)
-- .build();
-- }
--
-- @Test(expected = IllegalArgumentException.class)
-- public void testJdkServerEnableOcsp() throws Exception {
-- SelfSignedCertificate ssc = new SelfSignedCertificate();
-- try {
-- SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey())
-- .sslProvider(SslProvider.JDK)
-- .enableOcsp(true)
-- .build();
-- } finally {
-- ssc.delete();
-- }
-- }
--
-- @Test(expected = IllegalStateException.class)
-- public void testClientOcspNotEnabledOpenSsl() throws Exception {
-- testClientOcspNotEnabled(SslProvider.OPENSSL);
-- }
--
-- @Test(expected = IllegalStateException.class)
-- public void testClientOcspNotEnabledOpenSslRefCnt() throws Exception {
-- testClientOcspNotEnabled(SslProvider.OPENSSL_REFCNT);
-- }
--
-- private void testClientOcspNotEnabled(SslProvider sslProvider) throws Exception {
-- SslContext context = SslContextBuilder.forClient()
-- .sslProvider(sslProvider)
-- .build();
-- try {
-- SslHandler sslHandler = context.newHandler(ByteBufAllocator.DEFAULT);
-- ReferenceCountedOpenSslEngine engine = (ReferenceCountedOpenSslEngine) sslHandler.engine();
-- try {
-- engine.getOcspResponse();
-- } finally {
-- engine.release();
-- }
-- } finally {
-- ReferenceCountUtil.release(context);
-- }
-- }
--
-- @Test(expected = IllegalStateException.class)
-- public void testServerOcspNotEnabledOpenSsl() throws Exception {
-- testServerOcspNotEnabled(SslProvider.OPENSSL);
-- }
--
-- @Test(expected = IllegalStateException.class)
-- public void testServerOcspNotEnabledOpenSslRefCnt() throws Exception {
-- testServerOcspNotEnabled(SslProvider.OPENSSL_REFCNT);
-- }
--
-- private void testServerOcspNotEnabled(SslProvider sslProvider) throws Exception {
-- SelfSignedCertificate ssc = new SelfSignedCertificate();
-- try {
-- SslContext context = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey())
-- .sslProvider(sslProvider)
-- .build();
-- try {
-- SslHandler sslHandler = context.newHandler(ByteBufAllocator.DEFAULT);
-- ReferenceCountedOpenSslEngine engine = (ReferenceCountedOpenSslEngine) sslHandler.engine();
-- try {
-- engine.setOcspResponse(new byte[] { 1, 2, 3 });
-- } finally {
-- engine.release();
-- }
-- } finally {
-- ReferenceCountUtil.release(context);
-- }
-- } finally {
-- ssc.delete();
-- }
-- }
--
-- @Test(timeout = 10000L)
-- public void testClientAcceptingOcspStapleOpenSsl() throws Exception {
-- testClientAcceptingOcspStaple(SslProvider.OPENSSL);
-- }
--
-- @Test(timeout = 10000L)
-- public void testClientAcceptingOcspStapleOpenSslRefCnt() throws Exception {
-- testClientAcceptingOcspStaple(SslProvider.OPENSSL_REFCNT);
-- }
--
-- /**
-- * The Server provides an OCSP staple and the Client accepts it.
-- */
-- private void testClientAcceptingOcspStaple(SslProvider sslProvider) throws Exception {
-- final CountDownLatch latch = new CountDownLatch(1);
-- ChannelInboundHandlerAdapter serverHandler = new ChannelInboundHandlerAdapter() {
-- @Override
-- public void channelActive(ChannelHandlerContext ctx) throws Exception {
-- ctx.writeAndFlush(Unpooled.wrappedBuffer("Hello, World!".getBytes()));
-- ctx.fireChannelActive();
-- }
-- };
--
-- ChannelInboundHandlerAdapter clientHandler = new ChannelInboundHandlerAdapter() {
-- @Override
-- public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
-- try {
-- ReferenceCountUtil.release(msg);
-- } finally {
-- latch.countDown();
-- }
-- }
-- };
--
-- byte[] response = newOcspResponse();
-- TestClientOcspContext callback = new TestClientOcspContext(true);
--
-- handshake(sslProvider, latch, serverHandler, response, clientHandler, callback);
--
-- byte[] actual = callback.response();
--
-- assertNotNull(actual);
-- assertNotSame(response, actual);
-- assertArrayEquals(response, actual);
-- }
--
-- @Test(timeout = 10000L)
-- public void testClientRejectingOcspStapleOpenSsl() throws Exception {
-- testClientRejectingOcspStaple(SslProvider.OPENSSL);
-- }
--
-- @Test(timeout = 10000L)
-- public void testClientRejectingOcspStapleOpenSslRefCnt() throws Exception {
-- testClientRejectingOcspStaple(SslProvider.OPENSSL_REFCNT);
-- }
--
-- /**
-- * The Server provides an OCSP staple and the Client rejects it.
-- */
-- private void testClientRejectingOcspStaple(SslProvider sslProvider) throws Exception {
-- final AtomicReference<Throwable> causeRef = new AtomicReference<Throwable>();
-- final CountDownLatch latch = new CountDownLatch(1);
--
-- ChannelInboundHandlerAdapter clientHandler = new ChannelInboundHandlerAdapter() {
-- @Override
-- public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
-- try {
-- causeRef.set(cause);
-- } finally {
-- latch.countDown();
-- }
-- }
-- };
--
-- byte[] response = newOcspResponse();
-- TestClientOcspContext callback = new TestClientOcspContext(false);
--
-- handshake(sslProvider, latch, null, response, clientHandler, callback);
--
-- byte[] actual = callback.response();
--
-- assertNotNull(actual);
-- assertNotSame(response, actual);
-- assertArrayEquals(response, actual);
--
-- Throwable cause = causeRef.get();
-- assertTrue("" + cause, cause instanceof SSLHandshakeException);
-- }
--
-- @Test(timeout = 10000L)
-- public void testServerHasNoStapleOpenSsl() throws Exception {
-- testServerHasNoStaple(SslProvider.OPENSSL);
-- }
--
-- @Test(timeout = 10000L)
-- public void testServerHasNoStapleOpenSslRefCnt() throws Exception {
-- testServerHasNoStaple(SslProvider.OPENSSL_REFCNT);
-- }
--
-- /**
-- * The server has OCSP stapling enabled but doesn't provide a staple.
-- */
-- private void testServerHasNoStaple(SslProvider sslProvider) throws Exception {
-- final CountDownLatch latch = new CountDownLatch(1);
-- ChannelInboundHandlerAdapter serverHandler = new ChannelInboundHandlerAdapter() {
-- @Override
-- public void channelActive(ChannelHandlerContext ctx) throws Exception {
-- ctx.writeAndFlush(Unpooled.wrappedBuffer("Hello, World!".getBytes()));
-- ctx.fireChannelActive();
-- }
-- };
--
-- ChannelInboundHandlerAdapter clientHandler = new ChannelInboundHandlerAdapter() {
-- @Override
-- public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
-- try {
-- ReferenceCountUtil.release(msg);
-- } finally {
-- latch.countDown();
-- }
-- }
-- };
--
-- byte[] response = null;
-- TestClientOcspContext callback = new TestClientOcspContext(true);
--
-- handshake(sslProvider, latch, serverHandler, response, clientHandler, callback);
--
-- byte[] actual = callback.response();
--
-- assertNull(response);
-- assertNull(actual);
-- }
+-/**
+- * A handler for SSL clients to handle and act upon stapled OCSP responses.
+- *
+- * @see ReferenceCountedOpenSslContext#enableOcsp()
+- * @see ReferenceCountedOpenSslEngine#getOcspResponse()
+- */
+-@UnstableApi
+-public abstract class OcspClientHandler extends ChannelInboundHandlerAdapter {
-
-- @Test(timeout = 10000L)
-- public void testClientExceptionOpenSsl() throws Exception {
-- testClientException(SslProvider.OPENSSL);
-- }
+- private final ReferenceCountedOpenSslEngine engine;
-
-- @Test(timeout = 10000L)
-- public void testClientExceptionOpenSslRefCnt() throws Exception {
-- testClientException(SslProvider.OPENSSL_REFCNT);
+- protected OcspClientHandler(ReferenceCountedOpenSslEngine engine) {
+- this.engine = ObjectUtil.checkNotNull(engine, "engine");
- }
-
- /**
-- * Testing what happens if the {@link OcspClientCallback} throws an {@link Exception}.
-- *
-- * The exception should bubble up on the client side and the connection should get closed.
+- * @see ReferenceCountedOpenSslEngine#getOcspResponse()
- */
-- private void testClientException(SslProvider sslProvider) throws Exception {
-- final AtomicReference<Throwable> causeRef = new AtomicReference<Throwable>();
-- final CountDownLatch latch = new CountDownLatch(1);
--
-- ChannelInboundHandlerAdapter clientHandler = new ChannelInboundHandlerAdapter() {
-- @Override
-- public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
-- try {
-- causeRef.set(cause);
-- } finally {
-- latch.countDown();
-- }
-- }
-- };
--
-- final OcspTestException clientException = new OcspTestException("testClientException");
-- byte[] response = newOcspResponse();
-- OcspClientCallback callback = new OcspClientCallback() {
-- @Override
-- public boolean verify(byte[] response) throws Exception {
-- throw clientException;
-- }
-- };
--
-- handshake(sslProvider, latch, null, response, clientHandler, callback);
--
-- assertSame(clientException, causeRef.get());
-- }
--
-- private static void handshake(SslProvider sslProvider, CountDownLatch latch, ChannelHandler serverHandler,
-- byte[] response, ChannelHandler clientHandler, OcspClientCallback callback) throws Exception {
--
-- SelfSignedCertificate ssc = new SelfSignedCertificate();
-- try {
-- SslContext serverSslContext = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey())
-- .sslProvider(sslProvider)
-- .enableOcsp(true)
-- .build();
--
-- try {
-- SslContext clientSslContext = SslContextBuilder.forClient()
-- .sslProvider(sslProvider)
-- .enableOcsp(true)
-- .trustManager(InsecureTrustManagerFactory.INSTANCE)
-- .build();
--
-- try {
-- EventLoopGroup group = new DefaultEventLoopGroup();
-- try {
-- LocalAddress address = new LocalAddress("handshake-" + Math.random());
-- Channel server = newServer(group, address, serverSslContext, response, serverHandler);
-- Channel client = newClient(group, address, clientSslContext, callback, clientHandler);
-- try {
-- assertTrue("Something went wrong.", latch.await(10L, TimeUnit.SECONDS));
-- } finally {
-- client.close().syncUninterruptibly();
-- server.close().syncUninterruptibly();
-- }
-- } finally {
-- group.shutdownGracefully(1L, 1L, TimeUnit.SECONDS);
-- }
-- } finally {
-- ReferenceCountUtil.release(clientSslContext);
-- }
-- } finally {
-- ReferenceCountUtil.release(serverSslContext);
-- }
-- } finally {
-- ssc.delete();
-- }
-- }
--
-- private static Channel newServer(EventLoopGroup group, SocketAddress address,
-- SslContext context, byte[] response, ChannelHandler handler) {
--
-- ServerBootstrap bootstrap = new ServerBootstrap()
-- .channel(LocalServerChannel.class)
-- .group(group)
-- .childHandler(newServerHandler(context, response, handler));
--
-- return bootstrap.bind(address)
-- .syncUninterruptibly()
-- .channel();
-- }
--
-- private static Channel newClient(EventLoopGroup group, SocketAddress address,
-- SslContext context, OcspClientCallback callback, ChannelHandler handler) {
--
-- Bootstrap bootstrap = new Bootstrap()
-- .channel(LocalChannel.class)
-- .group(group)
-- .handler(newClientHandler(context, callback, handler));
--
-- return bootstrap.connect(address)
-- .syncUninterruptibly()
-- .channel();
-- }
--
-- private static ChannelHandler newServerHandler(final SslContext context,
-- final byte[] response, final ChannelHandler handler) {
-- return new ChannelInitializer<Channel>() {
-- @Override
-- protected void initChannel(Channel ch) throws Exception {
-- ChannelPipeline pipeline = ch.pipeline();
-- SslHandler sslHandler = context.newHandler(ch.alloc());
--
-- if (response != null) {
-- ReferenceCountedOpenSslEngine engine = (ReferenceCountedOpenSslEngine) sslHandler.engine();
-- engine.setOcspResponse(response);
-- }
--
-- pipeline.addLast(sslHandler);
--
-- if (handler != null) {
-- pipeline.addLast(handler);
-- }
-- }
-- };
-- }
--
-- private static ChannelHandler newClientHandler(final SslContext context,
-- final OcspClientCallback callback, final ChannelHandler handler) {
-- return new ChannelInitializer<Channel>() {
-- @Override
-- protected void initChannel(Channel ch) throws Exception {
-- ChannelPipeline pipeline = ch.pipeline();
--
-- SslHandler sslHandler = context.newHandler(ch.alloc());
-- ReferenceCountedOpenSslEngine engine = (ReferenceCountedOpenSslEngine) sslHandler.engine();
+- protected abstract boolean verify(ChannelHandlerContext ctx, ReferenceCountedOpenSslEngine engine) throws Exception;
-
-- pipeline.addLast(sslHandler);
-- pipeline.addLast(new OcspClientCallbackHandler(engine, callback));
+- @Override
+- public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
+- if (evt instanceof SslHandshakeCompletionEvent) {
+- ctx.pipeline().remove(this);
-
-- if (handler != null) {
-- pipeline.addLast(handler);
-- }
+- SslHandshakeCompletionEvent event = (SslHandshakeCompletionEvent) evt;
+- if (event.isSuccess() && !verify(ctx, engine)) {
+- throw new SSLHandshakeException("Bad OCSP response");
- }
-- };
-- }
--
-- private static byte[] newOcspResponse() {
-- // Assume we got the OCSP staple from somewhere. Using a bogus byte[]
-- // in the test because getting a true staple from the CA is quite involved.
-- // It requires HttpCodec and Bouncycastle and the test may be very unreliable
-- // because the OCSP responder servers are basically being DDoS'd by the
-- // Internet.
--
-- return "I am a bogus OCSP staple. OpenSSL does not care about the format of the byte[]!"
-- .getBytes(CharsetUtil.US_ASCII);
-- }
--
-- private interface OcspClientCallback {
-- boolean verify(byte[] staple) throws Exception;
-- }
--
-- private static final class TestClientOcspContext implements OcspClientCallback {
--
-- private final CountDownLatch latch = new CountDownLatch(1);
-- private final boolean valid;
--
-- private volatile byte[] response;
--
-- public TestClientOcspContext(boolean valid) {
-- this.valid = valid;
-- }
--
-- public byte[] response() throws InterruptedException, TimeoutException {
-- assertTrue(latch.await(10L, TimeUnit.SECONDS));
-- return response;
-- }
--
-- @Override
-- public boolean verify(byte[] response) throws Exception {
-- this.response = response;
-- latch.countDown();
--
-- return valid;
-- }
-- }
--
-- private static final class OcspClientCallbackHandler extends OcspClientHandler {
--
-- private final OcspClientCallback callback;
--
-- public OcspClientCallbackHandler(ReferenceCountedOpenSslEngine engine, OcspClientCallback callback) {
-- super(engine);
-- this.callback = callback;
-- }
--
-- @Override
-- protected boolean verify(ChannelHandlerContext ctx, ReferenceCountedOpenSslEngine engine) throws Exception {
-- byte[] response = engine.getOcspResponse();
-- return callback.verify(response);
- }
-- }
-
-- private static final class OcspTestException extends IllegalStateException {
-- public OcspTestException(String message) {
-- super(message);
-- }
+- ctx.fireUserEventTriggered(evt);
- }
-}
+diff --git a/handler/src/main/java/io/netty/handler/ssl/ocsp/package-info.java b/handler/src/main/java/io/netty/handler/ssl/ocsp/package-info.java
+deleted file mode 100644
+index 2883ff48cf..0000000000
+--- a/handler/src/main/java/io/netty/handler/ssl/ocsp/package-info.java
++++ /dev/null
+@@ -1,23 +0,0 @@
+-/*
+- * Copyright 2017 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- * http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-
+-/**
+- * <a href="https://en.wikipedia.org/wiki/OCSP_stapling">OCSP stapling</a>,
+- * formally known as the TLS Certificate Status Request extension, is an
+- * alternative approach to the Online Certificate Status Protocol (OCSP)
+- * for checking the revocation status of X.509 digital certificates.
+- */
+-package io.netty.handler.ssl.ocsp;
+diff --git a/pom.xml b/pom.xml
+index bedd6d6903..75a2da328a 100644
+--- a/pom.xml
++++ b/pom.xml
+@@ -465,16 +465,6 @@
+ <version>3.0.0-alpha-5</version>
+ </dependency>
+
+- <!-- Our own Tomcat Native fork - completely optional, used for accelerating SSL with OpenSSL. -->
+- <dependency>
+- <groupId>${project.groupId}</groupId>
+- <artifactId>${tcnative.artifactId}</artifactId>
+- <version>${tcnative.version}</version>
+- <classifier>${tcnative.classifier}</classifier>
+- <scope>compile</scope>
+- <optional>true</optional>
+- </dependency>
+-
+ <!--
+ Bouncy Castle - completely optional, only needed when:
+ - you generate a temporary self-signed certificate using SelfSignedCertificate, and
--
-2.9.4
+2.26.2
diff --git a/0005-Remove-optional-dep-log4j.patch b/0005-Remove-optional-dep-log4j.patch
new file mode 100644
index 0000000..9dcd6e7
--- /dev/null
+++ b/0005-Remove-optional-dep-log4j.patch
@@ -0,0 +1,911 @@
+From 1762f36e7ed797747ae692ea2c78001d45b35449 Mon Sep 17 00:00:00 2001
+From: Mat Booth <mat.booth(a)redhat.com>
+Date: Mon, 7 Sep 2020 14:29:44 +0100
+Subject: [PATCH 5/5] Remove optional dep log4j
+
+---
+ common/pom.xml | 15 -
+ .../logging/InternalLoggerFactory.java | 14 +-
+ .../util/internal/logging/Log4J2Logger.java | 143 -----
+ .../internal/logging/Log4J2LoggerFactory.java | 35 -
+ .../util/internal/logging/Log4JLogger.java | 597 ------------------
+ .../internal/logging/Log4JLoggerFactory.java | 40 --
+ 6 files changed, 2 insertions(+), 842 deletions(-)
+ delete mode 100644 common/src/main/java/io/netty/util/internal/logging/Log4J2Logger.java
+ delete mode 100644 common/src/main/java/io/netty/util/internal/logging/Log4J2LoggerFactory.java
+ delete mode 100644 common/src/main/java/io/netty/util/internal/logging/Log4JLogger.java
+ delete mode 100644 common/src/main/java/io/netty/util/internal/logging/Log4JLoggerFactory.java
+
+diff --git a/common/pom.xml b/common/pom.xml
+index abc73161eb..60693fb81a 100644
+--- a/common/pom.xml
++++ b/common/pom.xml
+@@ -63,21 +63,6 @@
+ <artifactId>commons-logging</artifactId>
+ <optional>true</optional>
+ </dependency>
+- <dependency>
+- <groupId>log4j</groupId>
+- <artifactId>log4j</artifactId>
+- <optional>true</optional>
+- </dependency>
+- <dependency>
+- <groupId>org.apache.logging.log4j</groupId>
+- <artifactId>log4j-api</artifactId>
+- <optional>true</optional>
+- </dependency>
+- <dependency>
+- <groupId>org.apache.logging.log4j</groupId>
+- <artifactId>log4j-core</artifactId>
+- <scope>test</scope>
+- </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-core</artifactId>
+diff --git a/common/src/main/java/io/netty/util/internal/logging/InternalLoggerFactory.java b/common/src/main/java/io/netty/util/internal/logging/InternalLoggerFactory.java
+index 508f571820..98eb4e4f4d 100644
+--- a/common/src/main/java/io/netty/util/internal/logging/InternalLoggerFactory.java
++++ b/common/src/main/java/io/netty/util/internal/logging/InternalLoggerFactory.java
+@@ -44,18 +44,8 @@ public abstract class InternalLoggerFactory {
+ f = new Slf4JLoggerFactory(true);
+ f.newInstance(name).debug("Using SLF4J as the default logging framework");
+ } catch (Throwable ignore1) {
+- try {
+- f = Log4J2LoggerFactory.INSTANCE;
+- f.newInstance(name).debug("Using Log4J2 as the default logging framework");
+- } catch (Throwable ignore2) {
+- try {
+- f = Log4JLoggerFactory.INSTANCE;
+- f.newInstance(name).debug("Using Log4J as the default logging framework");
+- } catch (Throwable ignore3) {
+- f = JdkLoggerFactory.INSTANCE;
+- f.newInstance(name).debug("Using java.util.logging as the default logging framework");
+- }
+- }
++ f = JdkLoggerFactory.INSTANCE;
++ f.newInstance(name).debug("Using java.util.logging as the default logging framework");
+ }
+ return f;
+ }
+diff --git a/common/src/main/java/io/netty/util/internal/logging/Log4J2Logger.java b/common/src/main/java/io/netty/util/internal/logging/Log4J2Logger.java
+deleted file mode 100644
+index 5c3593f203..0000000000
+--- a/common/src/main/java/io/netty/util/internal/logging/Log4J2Logger.java
++++ /dev/null
+@@ -1,143 +0,0 @@
+-/*
+- * Copyright 2016 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- * http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-package io.netty.util.internal.logging;
+-
+-
+-import org.apache.logging.log4j.Level;
+-import org.apache.logging.log4j.Logger;
+-import org.apache.logging.log4j.spi.ExtendedLogger;
+-import org.apache.logging.log4j.spi.ExtendedLoggerWrapper;
+-
+-import java.security.AccessController;
+-import java.security.PrivilegedAction;
+-
+-import static io.netty.util.internal.logging.AbstractInternalLogger.EXCEPTION_MESSAGE;
+-
+-class Log4J2Logger extends ExtendedLoggerWrapper implements InternalLogger {
+-
+- private static final long serialVersionUID = 5485418394879791397L;
+- private static final boolean VARARGS_ONLY;
+-
+- static {
+- // Older Log4J2 versions have only log methods that takes the format + varargs. So we should not use
+- // Log4J2 if the version is too old.
+- // See https://github.com/netty/netty/issues/8217
+- VARARGS_ONLY = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
+- @Override
+- public Boolean run() {
+- try {
+- Logger.class.getMethod("debug", String.class, Object.class);
+- return false;
+- } catch (NoSuchMethodException ignore) {
+- // Log4J2 version too old.
+- return true;
+- } catch (SecurityException ignore) {
+- // We could not detect the version so we will use Log4J2 if its on the classpath.
+- return false;
+- }
+- }
+- });
+- }
+-
+- Log4J2Logger(Logger logger) {
+- super((ExtendedLogger) logger, logger.getName(), logger.getMessageFactory());
+- if (VARARGS_ONLY) {
+- throw new UnsupportedOperationException("Log4J2 version mismatch");
+- }
+- }
+-
+- @Override
+- public String name() {
+- return getName();
+- }
+-
+- @Override
+- public void trace(Throwable t) {
+- log(Level.TRACE, EXCEPTION_MESSAGE, t);
+- }
+-
+- @Override
+- public void debug(Throwable t) {
+- log(Level.DEBUG, EXCEPTION_MESSAGE, t);
+- }
+-
+- @Override
+- public void info(Throwable t) {
+- log(Level.INFO, EXCEPTION_MESSAGE, t);
+- }
+-
+- @Override
+- public void warn(Throwable t) {
+- log(Level.WARN, EXCEPTION_MESSAGE, t);
+- }
+-
+- @Override
+- public void error(Throwable t) {
+- log(Level.ERROR, EXCEPTION_MESSAGE, t);
+- }
+-
+- @Override
+- public boolean isEnabled(InternalLogLevel level) {
+- return isEnabled(toLevel(level));
+- }
+-
+- @Override
+- public void log(InternalLogLevel level, String msg) {
+- log(toLevel(level), msg);
+- }
+-
+- @Override
+- public void log(InternalLogLevel level, String format, Object arg) {
+- log(toLevel(level), format, arg);
+- }
+-
+- @Override
+- public void log(InternalLogLevel level, String format, Object argA, Object argB) {
+- log(toLevel(level), format, argA, argB);
+- }
+-
+- @Override
+- public void log(InternalLogLevel level, String format, Object... arguments) {
+- log(toLevel(level), format, arguments);
+- }
+-
+- @Override
+- public void log(InternalLogLevel level, String msg, Throwable t) {
+- log(toLevel(level), msg, t);
+- }
+-
+- @Override
+- public void log(InternalLogLevel level, Throwable t) {
+- log(toLevel(level), EXCEPTION_MESSAGE, t);
+- }
+-
+- private static Level toLevel(InternalLogLevel level) {
+- switch (level) {
+- case INFO:
+- return Level.INFO;
+- case DEBUG:
+- return Level.DEBUG;
+- case WARN:
+- return Level.WARN;
+- case ERROR:
+- return Level.ERROR;
+- case TRACE:
+- return Level.TRACE;
+- default:
+- throw new Error();
+- }
+- }
+-}
+diff --git a/common/src/main/java/io/netty/util/internal/logging/Log4J2LoggerFactory.java b/common/src/main/java/io/netty/util/internal/logging/Log4J2LoggerFactory.java
+deleted file mode 100644
+index 8b895fbc07..0000000000
+--- a/common/src/main/java/io/netty/util/internal/logging/Log4J2LoggerFactory.java
++++ /dev/null
+@@ -1,35 +0,0 @@
+-/*
+- * Copyright 2016 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- * http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-package io.netty.util.internal.logging;
+-
+-import org.apache.logging.log4j.LogManager;
+-
+-public final class Log4J2LoggerFactory extends InternalLoggerFactory {
+-
+- public static final InternalLoggerFactory INSTANCE = new Log4J2LoggerFactory();
+-
+- /**
+- * @deprecated Use {@link #INSTANCE} instead.
+- */
+- @Deprecated
+- public Log4J2LoggerFactory() {
+- }
+-
+- @Override
+- public InternalLogger newInstance(String name) {
+- return new Log4J2Logger(LogManager.getLogger(name));
+- }
+-}
+diff --git a/common/src/main/java/io/netty/util/internal/logging/Log4JLogger.java b/common/src/main/java/io/netty/util/internal/logging/Log4JLogger.java
+deleted file mode 100644
+index 27b9130a08..0000000000
+--- a/common/src/main/java/io/netty/util/internal/logging/Log4JLogger.java
++++ /dev/null
+@@ -1,597 +0,0 @@
+-/*
+- * Copyright 2012 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- * http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-/**
+- * Copyright (c) 2004-2011 QOS.ch
+- * All rights reserved.
+- *
+- * Permission is hereby granted, free of charge, to any person obtaining
+- * a copy of this software and associated documentation files (the
+- * "Software"), to deal in the Software without restriction, including
+- * without limitation the rights to use, copy, modify, merge, publish,
+- * distribute, sublicense, and/or sell copies of the Software, and to
+- * permit persons to whom the Software is furnished to do so, subject to
+- * the following conditions:
+- *
+- * The above copyright notice and this permission notice shall be
+- * included in all copies or substantial portions of the Software.
+- *
+- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+- *
+- */
+-package io.netty.util.internal.logging;
+-
+-import org.apache.log4j.Level;
+-import org.apache.log4j.Logger;
+-
+-/**
+- * <a href="http://logging.apache.org/log4j/1.2/index.html">Apache Log4J</a>
+- * logger.
+- */
+-class Log4JLogger extends AbstractInternalLogger {
+-
+- private static final long serialVersionUID = 2851357342488183058L;
+-
+- final transient Logger logger;
+-
+- /**
+- * Following the pattern discussed in pages 162 through 168 of "The complete
+- * log4j manual".
+- */
+- static final String FQCN = Log4JLogger.class.getName();
+-
+- // Does the log4j version in use recognize the TRACE level?
+- // The trace level was introduced in log4j 1.2.12.
+- final boolean traceCapable;
+-
+- Log4JLogger(Logger logger) {
+- super(logger.getName());
+- this.logger = logger;
+- traceCapable = isTraceCapable();
+- }
+-
+- private boolean isTraceCapable() {
+- try {
+- logger.isTraceEnabled();
+- return true;
+- } catch (NoSuchMethodError ignored) {
+- return false;
+- }
+- }
+-
+- /**
+- * Is this logger instance enabled for the TRACE level?
+- *
+- * @return True if this Logger is enabled for level TRACE, false otherwise.
+- */
+- @Override
+- public boolean isTraceEnabled() {
+- if (traceCapable) {
+- return logger.isTraceEnabled();
+- } else {
+- return logger.isDebugEnabled();
+- }
+- }
+-
+- /**
+- * Log a message object at level TRACE.
+- *
+- * @param msg
+- * - the message object to be logged
+- */
+- @Override
+- public void trace(String msg) {
+- logger.log(FQCN, traceCapable ? Level.TRACE : Level.DEBUG, msg, null);
+- }
+-
+- /**
+- * Log a message at level TRACE according to the specified format and
+- * argument.
+- *
+- * <p>
+- * This form avoids superfluous object creation when the logger is disabled
+- * for level TRACE.
+- * </p>
+- *
+- * @param format
+- * the format string
+- * @param arg
+- * the argument
+- */
+- @Override
+- public void trace(String format, Object arg) {
+- if (isTraceEnabled()) {
+- FormattingTuple ft = MessageFormatter.format(format, arg);
+- logger.log(FQCN, traceCapable ? Level.TRACE : Level.DEBUG, ft
+- .getMessage(), ft.getThrowable());
+- }
+- }
+-
+- /**
+- * Log a message at level TRACE according to the specified format and
+- * arguments.
+- *
+- * <p>
+- * This form avoids superfluous object creation when the logger is disabled
+- * for the TRACE level.
+- * </p>
+- *
+- * @param format
+- * the format string
+- * @param argA
+- * the first argument
+- * @param argB
+- * the second argument
+- */
+- @Override
+- public void trace(String format, Object argA, Object argB) {
+- if (isTraceEnabled()) {
+- FormattingTuple ft = MessageFormatter.format(format, argA, argB);
+- logger.log(FQCN, traceCapable ? Level.TRACE : Level.DEBUG, ft
+- .getMessage(), ft.getThrowable());
+- }
+- }
+-
+- /**
+- * Log a message at level TRACE according to the specified format and
+- * arguments.
+- *
+- * <p>
+- * This form avoids superfluous object creation when the logger is disabled
+- * for the TRACE level.
+- * </p>
+- *
+- * @param format
+- * the format string
+- * @param arguments
+- * an array of arguments
+- */
+- @Override
+- public void trace(String format, Object... arguments) {
+- if (isTraceEnabled()) {
+- FormattingTuple ft = MessageFormatter.arrayFormat(format, arguments);
+- logger.log(FQCN, traceCapable ? Level.TRACE : Level.DEBUG, ft
+- .getMessage(), ft.getThrowable());
+- }
+- }
+-
+- /**
+- * Log an exception (throwable) at level TRACE with an accompanying message.
+- *
+- * @param msg
+- * the message accompanying the exception
+- * @param t
+- * the exception (throwable) to log
+- */
+- @Override
+- public void trace(String msg, Throwable t) {
+- logger.log(FQCN, traceCapable ? Level.TRACE : Level.DEBUG, msg, t);
+- }
+-
+- /**
+- * Is this logger instance enabled for the DEBUG level?
+- *
+- * @return True if this Logger is enabled for level DEBUG, false otherwise.
+- */
+- @Override
+- public boolean isDebugEnabled() {
+- return logger.isDebugEnabled();
+- }
+-
+- /**
+- * Log a message object at level DEBUG.
+- *
+- * @param msg
+- * - the message object to be logged
+- */
+- @Override
+- public void debug(String msg) {
+- logger.log(FQCN, Level.DEBUG, msg, null);
+- }
+-
+- /**
+- * Log a message at level DEBUG according to the specified format and
+- * argument.
+- *
+- * <p>
+- * This form avoids superfluous object creation when the logger is disabled
+- * for level DEBUG.
+- * </p>
+- *
+- * @param format
+- * the format string
+- * @param arg
+- * the argument
+- */
+- @Override
+- public void debug(String format, Object arg) {
+- if (logger.isDebugEnabled()) {
+- FormattingTuple ft = MessageFormatter.format(format, arg);
+- logger.log(FQCN, Level.DEBUG, ft.getMessage(), ft.getThrowable());
+- }
+- }
+-
+- /**
+- * Log a message at level DEBUG according to the specified format and
+- * arguments.
+- *
+- * <p>
+- * This form avoids superfluous object creation when the logger is disabled
+- * for the DEBUG level.
+- * </p>
+- *
+- * @param format
+- * the format string
+- * @param argA
+- * the first argument
+- * @param argB
+- * the second argument
+- */
+- @Override
+- public void debug(String format, Object argA, Object argB) {
+- if (logger.isDebugEnabled()) {
+- FormattingTuple ft = MessageFormatter.format(format, argA, argB);
+- logger.log(FQCN, Level.DEBUG, ft.getMessage(), ft.getThrowable());
+- }
+- }
+-
+- /**
+- * Log a message at level DEBUG according to the specified format and
+- * arguments.
+- *
+- * <p>
+- * This form avoids superfluous object creation when the logger is disabled
+- * for the DEBUG level.
+- * </p>
+- *
+- * @param format
+- * the format string
+- * @param arguments an array of arguments
+- */
+- @Override
+- public void debug(String format, Object... arguments) {
+- if (logger.isDebugEnabled()) {
+- FormattingTuple ft = MessageFormatter.arrayFormat(format, arguments);
+- logger.log(FQCN, Level.DEBUG, ft.getMessage(), ft.getThrowable());
+- }
+- }
+-
+- /**
+- * Log an exception (throwable) at level DEBUG with an accompanying message.
+- *
+- * @param msg
+- * the message accompanying the exception
+- * @param t
+- * the exception (throwable) to log
+- */
+- @Override
+- public void debug(String msg, Throwable t) {
+- logger.log(FQCN, Level.DEBUG, msg, t);
+- }
+-
+- /**
+- * Is this logger instance enabled for the INFO level?
+- *
+- * @return True if this Logger is enabled for the INFO level, false otherwise.
+- */
+- @Override
+- public boolean isInfoEnabled() {
+- return logger.isInfoEnabled();
+- }
+-
+- /**
+- * Log a message object at the INFO level.
+- *
+- * @param msg
+- * - the message object to be logged
+- */
+- @Override
+- public void info(String msg) {
+- logger.log(FQCN, Level.INFO, msg, null);
+- }
+-
+- /**
+- * Log a message at level INFO according to the specified format and argument.
+- *
+- * <p>
+- * This form avoids superfluous object creation when the logger is disabled
+- * for the INFO level.
+- * </p>
+- *
+- * @param format
+- * the format string
+- * @param arg
+- * the argument
+- */
+- @Override
+- public void info(String format, Object arg) {
+- if (logger.isInfoEnabled()) {
+- FormattingTuple ft = MessageFormatter.format(format, arg);
+- logger.log(FQCN, Level.INFO, ft.getMessage(), ft.getThrowable());
+- }
+- }
+-
+- /**
+- * Log a message at the INFO level according to the specified format and
+- * arguments.
+- *
+- * <p>
+- * This form avoids superfluous object creation when the logger is disabled
+- * for the INFO level.
+- * </p>
+- *
+- * @param format
+- * the format string
+- * @param argA
+- * the first argument
+- * @param argB
+- * the second argument
+- */
+- @Override
+- public void info(String format, Object argA, Object argB) {
+- if (logger.isInfoEnabled()) {
+- FormattingTuple ft = MessageFormatter.format(format, argA, argB);
+- logger.log(FQCN, Level.INFO, ft.getMessage(), ft.getThrowable());
+- }
+- }
+-
+- /**
+- * Log a message at level INFO according to the specified format and
+- * arguments.
+- *
+- * <p>
+- * This form avoids superfluous object creation when the logger is disabled
+- * for the INFO level.
+- * </p>
+- *
+- * @param format
+- * the format string
+- * @param argArray
+- * an array of arguments
+- */
+- @Override
+- public void info(String format, Object... argArray) {
+- if (logger.isInfoEnabled()) {
+- FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray);
+- logger.log(FQCN, Level.INFO, ft.getMessage(), ft.getThrowable());
+- }
+- }
+-
+- /**
+- * Log an exception (throwable) at the INFO level with an accompanying
+- * message.
+- *
+- * @param msg
+- * the message accompanying the exception
+- * @param t
+- * the exception (throwable) to log
+- */
+- @Override
+- public void info(String msg, Throwable t) {
+- logger.log(FQCN, Level.INFO, msg, t);
+- }
+-
+- /**
+- * Is this logger instance enabled for the WARN level?
+- *
+- * @return True if this Logger is enabled for the WARN level, false otherwise.
+- */
+- @Override
+- public boolean isWarnEnabled() {
+- return logger.isEnabledFor(Level.WARN);
+- }
+-
+- /**
+- * Log a message object at the WARN level.
+- *
+- * @param msg
+- * - the message object to be logged
+- */
+- @Override
+- public void warn(String msg) {
+- logger.log(FQCN, Level.WARN, msg, null);
+- }
+-
+- /**
+- * Log a message at the WARN level according to the specified format and
+- * argument.
+- *
+- * <p>
+- * This form avoids superfluous object creation when the logger is disabled
+- * for the WARN level.
+- * </p>
+- *
+- * @param format
+- * the format string
+- * @param arg
+- * the argument
+- */
+- @Override
+- public void warn(String format, Object arg) {
+- if (logger.isEnabledFor(Level.WARN)) {
+- FormattingTuple ft = MessageFormatter.format(format, arg);
+- logger.log(FQCN, Level.WARN, ft.getMessage(), ft.getThrowable());
+- }
+- }
+-
+- /**
+- * Log a message at the WARN level according to the specified format and
+- * arguments.
+- *
+- * <p>
+- * This form avoids superfluous object creation when the logger is disabled
+- * for the WARN level.
+- * </p>
+- *
+- * @param format
+- * the format string
+- * @param argA
+- * the first argument
+- * @param argB
+- * the second argument
+- */
+- @Override
+- public void warn(String format, Object argA, Object argB) {
+- if (logger.isEnabledFor(Level.WARN)) {
+- FormattingTuple ft = MessageFormatter.format(format, argA, argB);
+- logger.log(FQCN, Level.WARN, ft.getMessage(), ft.getThrowable());
+- }
+- }
+-
+- /**
+- * Log a message at level WARN according to the specified format and
+- * arguments.
+- *
+- * <p>
+- * This form avoids superfluous object creation when the logger is disabled
+- * for the WARN level.
+- * </p>
+- *
+- * @param format
+- * the format string
+- * @param argArray
+- * an array of arguments
+- */
+- @Override
+- public void warn(String format, Object... argArray) {
+- if (logger.isEnabledFor(Level.WARN)) {
+- FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray);
+- logger.log(FQCN, Level.WARN, ft.getMessage(), ft.getThrowable());
+- }
+- }
+-
+- /**
+- * Log an exception (throwable) at the WARN level with an accompanying
+- * message.
+- *
+- * @param msg
+- * the message accompanying the exception
+- * @param t
+- * the exception (throwable) to log
+- */
+- @Override
+- public void warn(String msg, Throwable t) {
+- logger.log(FQCN, Level.WARN, msg, t);
+- }
+-
+- /**
+- * Is this logger instance enabled for level ERROR?
+- *
+- * @return True if this Logger is enabled for level ERROR, false otherwise.
+- */
+- @Override
+- public boolean isErrorEnabled() {
+- return logger.isEnabledFor(Level.ERROR);
+- }
+-
+- /**
+- * Log a message object at the ERROR level.
+- *
+- * @param msg
+- * - the message object to be logged
+- */
+- @Override
+- public void error(String msg) {
+- logger.log(FQCN, Level.ERROR, msg, null);
+- }
+-
+- /**
+- * Log a message at the ERROR level according to the specified format and
+- * argument.
+- *
+- * <p>
+- * This form avoids superfluous object creation when the logger is disabled
+- * for the ERROR level.
+- * </p>
+- *
+- * @param format
+- * the format string
+- * @param arg
+- * the argument
+- */
+- @Override
+- public void error(String format, Object arg) {
+- if (logger.isEnabledFor(Level.ERROR)) {
+- FormattingTuple ft = MessageFormatter.format(format, arg);
+- logger.log(FQCN, Level.ERROR, ft.getMessage(), ft.getThrowable());
+- }
+- }
+-
+- /**
+- * Log a message at the ERROR level according to the specified format and
+- * arguments.
+- *
+- * <p>
+- * This form avoids superfluous object creation when the logger is disabled
+- * for the ERROR level.
+- * </p>
+- *
+- * @param format
+- * the format string
+- * @param argA
+- * the first argument
+- * @param argB
+- * the second argument
+- */
+- @Override
+- public void error(String format, Object argA, Object argB) {
+- if (logger.isEnabledFor(Level.ERROR)) {
+- FormattingTuple ft = MessageFormatter.format(format, argA, argB);
+- logger.log(FQCN, Level.ERROR, ft.getMessage(), ft.getThrowable());
+- }
+- }
+-
+- /**
+- * Log a message at level ERROR according to the specified format and
+- * arguments.
+- *
+- * <p>
+- * This form avoids superfluous object creation when the logger is disabled
+- * for the ERROR level.
+- * </p>
+- *
+- * @param format
+- * the format string
+- * @param argArray
+- * an array of arguments
+- */
+- @Override
+- public void error(String format, Object... argArray) {
+- if (logger.isEnabledFor(Level.ERROR)) {
+- FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray);
+- logger.log(FQCN, Level.ERROR, ft.getMessage(), ft.getThrowable());
+- }
+- }
+-
+- /**
+- * Log an exception (throwable) at the ERROR level with an accompanying
+- * message.
+- *
+- * @param msg
+- * the message accompanying the exception
+- * @param t
+- * the exception (throwable) to log
+- */
+- @Override
+- public void error(String msg, Throwable t) {
+- logger.log(FQCN, Level.ERROR, msg, t);
+- }
+-}
+diff --git a/common/src/main/java/io/netty/util/internal/logging/Log4JLoggerFactory.java b/common/src/main/java/io/netty/util/internal/logging/Log4JLoggerFactory.java
+deleted file mode 100644
+index 399a279df3..0000000000
+--- a/common/src/main/java/io/netty/util/internal/logging/Log4JLoggerFactory.java
++++ /dev/null
+@@ -1,40 +0,0 @@
+-/*
+- * Copyright 2012 The Netty Project
+- *
+- * The Netty Project licenses this file to you under the Apache License,
+- * version 2.0 (the "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at:
+- *
+- * http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing, software
+- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+- * License for the specific language governing permissions and limitations
+- * under the License.
+- */
+-package io.netty.util.internal.logging;
+-
+-import org.apache.log4j.Logger;
+-
+-/**
+- * Logger factory which creates an
+- * <a href="http://logging.apache.org/log4j/1.2/index.html">Apache Log4J</a>
+- * logger.
+- */
+-public class Log4JLoggerFactory extends InternalLoggerFactory {
+-
+- public static final InternalLoggerFactory INSTANCE = new Log4JLoggerFactory();
+-
+- /**
+- * @deprecated Use {@link #INSTANCE} instead.
+- */
+- @Deprecated
+- public Log4JLoggerFactory() {
+- }
+-
+- @Override
+- public InternalLogger newInstance(String name) {
+- return new Log4JLogger(Logger.getLogger(name));
+- }
+-}
+--
+2.26.2
+
diff --git a/netty.spec b/netty.spec
index 5a630f0..90e1234 100644
--- a/netty.spec
+++ b/netty.spec
@@ -1,13 +1,9 @@
-# Disable generation of debuginfo package
-%global debug_package %{nil}
%global namedreltag .Final
%global namedversion %{version}%{?namedreltag}
-%bcond_without jp_minimal
-
Name: netty
-Version: 4.1.13
-Release: 19%{?dist}
+Version: 4.1.51
+Release: 1%{?dist}
Summary: An asynchronous event-driven network application framework and tools for Java
License: ASL 2.0
URL: https://netty.io/
@@ -16,42 +12,25 @@ Source0: https://github.com/netty/netty/archive/netty-%{namedversion}.tar
# We don't have the plugin and want to avoid groovy dependency
# This script is written in bash+sed and performs the same task
Source1: codegen.bash
-Patch0: 0001-Remove-OpenSSL-parts-depending-on-tcnative.patch
-Patch1: 0002-Remove-NPN.patch
-Patch2: 0003-Remove-conscrypt-ALPN.patch
-Patch3: 0004-Remove-jetty-ALPN.patch
+Patch0: 0001-Remove-optional-dep-Blockhound.patch
+Patch1: 0002-Remove-optional-dep-conscrypt.patch
+Patch2: 0003-Remove-optional-deps-jetty-alpn-and-npn.patch
+Patch3: 0004-Remove-optional-dep-tcnative.patch
+Patch4: 0005-Remove-optional-dep-log4j.patch
BuildRequires: maven-local
-BuildRequires: mvn(ant-contrib:ant-contrib)
BuildRequires: mvn(com.jcraft:jzlib)
BuildRequires: mvn(commons-logging:commons-logging)
BuildRequires: mvn(kr.motd.maven:os-maven-plugin)
-BuildRequires: mvn(log4j:log4j:1.2.17)
BuildRequires: mvn(org.apache.felix:maven-bundle-plugin)
-BuildRequires: mvn(org.apache.maven.plugins:maven-antrun-plugin)
-BuildRequires: mvn(org.apache.maven.plugins:maven-dependency-plugin)
BuildRequires: mvn(org.apache.maven.plugins:maven-remote-resources-plugin)
+BuildRequires: mvn(org.bouncycastle:bcpkix-jdk15on)
BuildRequires: mvn(org.codehaus.mojo:build-helper-maven-plugin)
BuildRequires: mvn(org.codehaus.mojo:exec-maven-plugin)
-BuildRequires: mvn(org.fusesource.hawtjni:maven-hawtjni-plugin)
BuildRequires: mvn(org.jctools:jctools-core)
BuildRequires: mvn(org.slf4j:slf4j-api)
-%if %{without jp_minimal}
-BuildRequires: mvn(com.fasterxml:aalto-xml)
-BuildRequires: mvn(com.github.jponge:lzma-java)
-BuildRequires: mvn(com.ning:compress-lzf)
-BuildRequires: mvn(net.jpountz.lz4:lz4)
-BuildRequires: mvn(org.apache.logging.log4j:log4j-api)
-BuildRequires: mvn(org.bouncycastle:bcpkix-jdk15on)
-BuildRequires: mvn(org.jboss.marshalling:jboss-marshalling)
-BuildRequires: mvn(org.eclipse.jetty.alpn:alpn-api)
-%endif
-%ifarch %{arm}
-# Speed up builds on 32bit arm
-# Disable temporarily due to https://bugzilla.redhat.com/show_bug.cgi?id=1818078
-#BuildRequires: java-1.8.0-openjdk-aarch32-devel
-%endif
+BuildArch: noarch
%description
Netty is a NIO client server framework which enables quick and easy
@@ -79,9 +58,8 @@ Summary: API documentation for %{name}
%patch0 -p1
%patch1 -p1
%patch2 -p1
-%if %{with jp_minimal}
%patch3 -p1
-%endif
+%patch4 -p1
# remove unnecessary dependency on parent POM
%pom_remove_parent . bom dev-tools
@@ -89,15 +67,8 @@ Summary: API documentation for %{name}
# Disable all in one jar
%pom_disable_module all
-# Missing Mavenized rxtx
-%pom_disable_module "transport-rxtx"
-# Missing com.barchart.udt:barchart-udt-bundle:jar:2.3.0
-%pom_disable_module "transport-udt"
-# Not needed
+# Not needed for RPM builds
%pom_disable_module "example"
-%pom_disable_module "testsuite"
-%pom_disable_module "testsuite-autobahn"
-%pom_disable_module "testsuite-osgi"
%pom_disable_module "tarball"
%pom_disable_module "microbench"
@@ -112,7 +83,6 @@ Summary: API documentation for %{name}
%pom_remove_plugin :maven-antrun-plugin
%pom_remove_plugin :maven-dependency-plugin
-# style checker
%pom_remove_plugin :xml-maven-plugin
%pom_remove_plugin -r :maven-checkstyle-plugin
%pom_remove_plugin -r :animal-sniffer-maven-plugin
@@ -143,6 +113,10 @@ cp %{SOURCE1} common/codegen.bash
'
%pom_remove_plugin :groovy-maven-plugin common
+# We don't have com.oracle.substratevm
+%pom_remove_dep "com.oracle.substratevm:" common
+rm common/src/main/java/io/netty/util/internal/svm/*
+
# The protobuf-javanano API was discontinued upstream and obsoleted in Fedora
# so disable support for protobuf in the codecs module
%pom_remove_dep -r "com.google.protobuf:protobuf-java"
@@ -150,31 +124,41 @@ cp %{SOURCE1} common/codegen.bash
rm codec/src/main/java/io/netty/handler/codec/protobuf/*
sed -i '/import.*protobuf/d' codec/src/main/java/io/netty/handler/codec/DatagramPacket*.java
-%if %{with jp_minimal}
+# JBoss marshalling not available in Fedora
%pom_remove_dep -r "org.jboss.marshalling:jboss-marshalling"
rm codec/src/main/java/io/netty/handler/codec/marshalling/*
-%pom_remove_dep -r org.bouncycastle
-rm handler/src/main/java/io/netty/handler/ssl/util/BouncyCastleSelfSignedCertGenerator.java
-sed -i '/BouncyCastleSelfSignedCertGenerator/s/.*/throw new UnsupportedOperationException();/' \
- handler/src/main/java/io/netty/handler/ssl/util/SelfSignedCertificate.java
-%pom_remove_dep -r com.fasterxml:aalto-xml
-%pom_disable_module codec-xml
+
+# Various compression codecs not available in Fedora
%pom_remove_dep -r com.github.jponge:lzma-java
rm codec/src/*/java/io/netty/handler/codec/compression/Lzma*.java
%pom_remove_dep -r com.ning:compress-lzf
rm codec/src/*/java/io/netty/handler/codec/compression/Lzf*.java
%pom_remove_dep -r net.jpountz.lz4:lz4
rm codec/src/*/java/io/netty/handler/codec/compression/Lz4*.java
-%pom_remove_dep -r org.apache.logging.log4j:
-rm common/*/main/java/io/netty/util/internal/logging/Log4J2*.java
-# Disable rarely needed native artifacts
+# Disable other codecs with extra dependencies
+%pom_remove_dep -r com.fasterxml:aalto-xml
+%pom_disable_module codec-xml
+
+# Disable unneeded transport artifacts
%pom_disable_module transport-native-epoll
%pom_disable_module transport-native-kqueue
-
-%endif
-
-%pom_xpath_inject "pom:execution[pom:id = 'build-native-lib']/pom:configuration" '<verbose>true</verbose>' transport-native-epoll/pom.xml
+%pom_disable_module transport-native-unix-common
+%pom_disable_module transport-rxtx
+%pom_disable_module transport-sctp
+%pom_disable_module transport-udt
+
+# Disable macos native bit
+%pom_disable_module resolver-dns-native-macos
+
+# Disable test suites
+%pom_disable_module testsuite
+%pom_disable_module testsuite-autobahn
+%pom_disable_module testsuite-http2
+%pom_disable_module testsuite-native-image
+%pom_disable_module testsuite-osgi
+%pom_disable_module testsuite-shading
+%pom_disable_module transport-native-unix-common-tests
# Upstream has jctools bundled.
%pom_xpath_remove "pom:build/pom:plugins/pom:plugin[pom:artifactId = 'maven-bundle-plugin']/pom:executions/pom:execution[pom:id = 'generate-manifest']/pom:configuration/pom:instructions/pom:Import-Package" common/pom.xml
@@ -184,11 +168,7 @@ rm common/*/main/java/io/netty/util/internal/logging/Log4J2*.java
# the linux classifier.
%mvn_package ":::linux*:"
-%mvn_package ':*-tests' __noinstall
-
%build
-export JAVA_HOME=%{_jvmdir}/java
-
# Ensure we use distro compile flags
export CFLAGS="$RPM_OPT_FLAGS" LDFLAGS="$RPM_LD_FLAGS"
@@ -204,6 +184,10 @@ export CFLAGS="$RPM_OPT_FLAGS" LDFLAGS="$RPM_LD_FLAGS"
%license LICENSE.txt NOTICE.txt
%changelog
+* Mon Sep 07 2020 Mat Booth <mat.booth(a)redhat.com> - 4.1.51-1
+- Update to latest upstream version
+- Native bits were not used by anything, so package is now noarch
+
* Tue Jul 28 2020 Fedora Release Engineering <releng(a)fedoraproject.org> - 4.1.13-19
- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild
diff --git a/sources b/sources
index 39533ac..a39ea3d 100644
--- a/sources
+++ b/sources
@@ -1 +1 @@
-SHA512 (netty-4.1.13.Final.tar.gz) = f0a269adf5b6552eb2f0f12614c2093e0ccfd5a5bb38521dcf39c3827160c8983adcfe1bbcf93a24e71506e323ae723a837621046657fec0df50c59a07aee54c
+SHA512 (netty-4.1.51.Final.tar.gz) = 3b6e00b48710ada4e2c3fbcd71a2c82804dded30c8fa99f10dc609e063642ab5351fe0c26183b03a429439d2351b51ca4cfe803e68dfc5929156faafb1a47800
3 years, 8 months
Architecture specific change in rpms/qemu.git
by githook-noreply@fedoraproject.org
The package rpms/qemu.git has added or updated architecture specific content in its
spec file (ExclusiveArch/ExcludeArch or %ifarch/%ifnarch) in commit(s):
https://src.fedoraproject.org/cgit/rpms/qemu.git/commit/?id=d9af2bbdff861...
https://src.fedoraproject.org/cgit/rpms/qemu.git/commit/?id=13e7c30edf2da...
https://src.fedoraproject.org/cgit/rpms/qemu.git/commit/?id=3c0f9e810a0b2....
Change:
+%ifarch %{arm} aarch64
-%ifarch %{kernel_arches}
-%ifarch s390
Thanks.
Full change:
============
commit d9af2bbdff8613c35c44d4a0ea29abcbf0065b68
Author: Daniel P. Berrangé <berrange(a)redhat.com>
Date: Fri Sep 4 11:03:27 2020 +0100
Make QEMU sanity check a build blocker
If it ever breaks, it can be skipped by setting the %qemu_sanity_check
variable to 0.
This ensures it does not bit-rot again in future and actually adds some
value to the build.
It has to be skipped for ARM for now due to inability to select the
machine type.
Signed-off-by: Daniel P. Berrangé <berrange(a)redhat.com>
diff --git a/qemu.spec b/qemu.spec
index 0eb999d..0a78ac8 100644
--- a/qemu.spec
+++ b/qemu.spec
@@ -86,6 +86,13 @@
%endif
%endif
+# QEMU sanity check doesn't know how to pick machine type
+# which is needed on ARM as there is no defualt
+# https://bugzilla.redhat.com/show_bug.cgi?id=1875763
+%ifarch %{arm} aarch64
+%global qemu_sanity_check 0
+%endif
+
# All modules should be listed here.
%ifarch %{ix86} %{arm}
%define with_block_rbd 0
@@ -1414,10 +1421,9 @@ if [ -x "$b" ]; then "$b" -help; fi
%if %{qemu_sanity_check}
# Sanity-check current kernel can boot on this qemu.
-# The results are advisory only.
KERNEL=`find /lib/modules -name vmlinuz | head -1`
echo "Trying to boot kernel $KERNEL with %{?hostqemu}"
-qemu-sanity-check --qemu=%{?hostqemu} --kernel=$KERNEL ||:
+qemu-sanity-check --qemu=%{?hostqemu} --kernel=$KERNEL
%endif
%endif
@@ -1906,6 +1912,7 @@ getent passwd qemu >/dev/null || \
- Fix conditionals for enabling QEMU sanity check
- Check whether emulator works before doing sanity check
- Provide explicit kernel path for QEMU sanity check
+- Make QEMU sanity check a build blocker
* Thu Sep 3 2020 Daniel P. Berrangé <berrange(a)redhat.com> - 5.1.0-4
- Add btrfs ioctls to linux-user (rhbz #1872918)
commit f2839fea71ecc8dbe7e38c0ec09e3e9ef6edb831
Author: Daniel P. Berrangé <berrange(a)redhat.com>
Date: Fri Sep 4 10:49:53 2020 +0100
Provide explicit kernel path to QEMU sanity check
In a mock build root the kernel probably won't exist in /boot and the
QEMU sanity check script won't search /lib/modules. So we must find the
vmlinuz file and pass it explicitly.
Signed-off-by: Daniel P. Berrangé <berrange(a)redhat.com>
diff --git a/qemu.spec b/qemu.spec
index 2aa30f8..0eb999d 100644
--- a/qemu.spec
+++ b/qemu.spec
@@ -1415,7 +1415,9 @@ if [ -x "$b" ]; then "$b" -help; fi
%if %{qemu_sanity_check}
# Sanity-check current kernel can boot on this qemu.
# The results are advisory only.
-qemu-sanity-check --qemu=%{?hostqemu} ||:
+KERNEL=`find /lib/modules -name vmlinuz | head -1`
+echo "Trying to boot kernel $KERNEL with %{?hostqemu}"
+qemu-sanity-check --qemu=%{?hostqemu} --kernel=$KERNEL ||:
%endif
%endif
@@ -1903,6 +1905,7 @@ getent passwd qemu >/dev/null || \
- Re-enable kernel BR for QEMU sanity check
- Fix conditionals for enabling QEMU sanity check
- Check whether emulator works before doing sanity check
+- Provide explicit kernel path for QEMU sanity check
* Thu Sep 3 2020 Daniel P. Berrangé <berrange(a)redhat.com> - 5.1.0-4
- Add btrfs ioctls to linux-user (rhbz #1872918)
commit af50bf7b783cee59cdf348e9263d5bb4a848148b
Author: Daniel P. Berrangé <berrange(a)redhat.com>
Date: Fri Sep 4 10:44:52 2020 +0100
Check whether emulator works before doing sanity check
If the emulator binary can't run, then the sanity check is never going
to work either.
Signed-off-by: Daniel P. Berrangé <berrange(a)redhat.com>
diff --git a/qemu.spec b/qemu.spec
index 9530011..2aa30f8 100644
--- a/qemu.spec
+++ b/qemu.spec
@@ -1408,16 +1408,16 @@ pushd build-dynamic
make check V=1
%endif
+# Check the binary runs (see eg RHBZ#998722).
+b="./x86_64-softmmu/qemu-system-x86_64"
+if [ -x "$b" ]; then "$b" -help; fi
+
%if %{qemu_sanity_check}
# Sanity-check current kernel can boot on this qemu.
# The results are advisory only.
qemu-sanity-check --qemu=%{?hostqemu} ||:
%endif
-# Check the binary runs (see eg RHBZ#998722).
-b="./x86_64-softmmu/qemu-system-x86_64"
-if [ -x "$b" ]; then "$b" -help; fi
-
%endif
popd
@@ -1902,6 +1902,7 @@ getent passwd qemu >/dev/null || \
- Fix host qemu binary path for aarch64
- Re-enable kernel BR for QEMU sanity check
- Fix conditionals for enabling QEMU sanity check
+- Check whether emulator works before doing sanity check
* Thu Sep 3 2020 Daniel P. Berrangé <berrange(a)redhat.com> - 5.1.0-4
- Add btrfs ioctls to linux-user (rhbz #1872918)
commit 13e7c30edf2da5fac2a78ec93d00039cf49b92b4
Author: Daniel P. Berrangé <berrange(a)redhat.com>
Date: Fri Sep 4 10:42:55 2020 +0100
Fix conditionals for enabling QEMU sanity check
One part of the spec file checked %{kernel_arches} while the other
checked %{hostqemu}. In fact both conditions need to be valid in
order to be able to run the sanity check. Introduce an explicit
%{qemu_sanity_check} variable to express this rule.
Signed-off-by: Daniel P. Berrangé <berrange(a)redhat.com>
diff --git a/qemu.spec b/qemu.spec
index 46ff04c..9530011 100644
--- a/qemu.spec
+++ b/qemu.spec
@@ -79,6 +79,13 @@
%global hostqemu x86_64-softmmu/qemu-system-x86_64
%endif
+%global qemu_sanity_check 0
+%ifarch x %{?kernel_arches}
+%if 0%{?hostqemu:1}
+%global qemu_sanity_check 1
+%endif
+%endif
+
# All modules should be listed here.
%ifarch %{ix86} %{arm}
%define with_block_rbd 0
@@ -210,8 +217,7 @@ BuildRequires: gcc
BuildRequires: texinfo
# For /usr/bin/pod2man
BuildRequires: perl-podlators
-%ifarch %{kernel_arches}
-# For sanity test
+%if %{qemu_sanity_check}
BuildRequires: qemu-sanity-check-nodeps
BuildRequires: kernel
%endif
@@ -1402,7 +1408,7 @@ pushd build-dynamic
make check V=1
%endif
-%if 0%{?hostqemu:1}
+%if %{qemu_sanity_check}
# Sanity-check current kernel can boot on this qemu.
# The results are advisory only.
qemu-sanity-check --qemu=%{?hostqemu} ||:
@@ -1895,6 +1901,7 @@ getent passwd qemu >/dev/null || \
- Drop conditions for ppc, ppc64, mips64 and s390 arches
- Fix host qemu binary path for aarch64
- Re-enable kernel BR for QEMU sanity check
+- Fix conditionals for enabling QEMU sanity check
* Thu Sep 3 2020 Daniel P. Berrangé <berrange(a)redhat.com> - 5.1.0-4
- Add btrfs ioctls to linux-user (rhbz #1872918)
commit 4e321e2f5cf77ed4387d86d41762848074cfaf8f
Author: Daniel P. Berrangé <berrange(a)redhat.com>
Date: Fri Sep 4 10:40:00 2020 +0100
Re-enable kernel BR for qemu sanity check
Signed-off-by: Daniel P. Berrangé <berrange(a)redhat.com>
diff --git a/qemu.spec b/qemu.spec
index eda3911..46ff04c 100644
--- a/qemu.spec
+++ b/qemu.spec
@@ -213,8 +213,7 @@ BuildRequires: perl-podlators
%ifarch %{kernel_arches}
# For sanity test
BuildRequires: qemu-sanity-check-nodeps
-# 2020-08-12: Disable due to new f34 missing kernel package
-#BuildRequires: kernel
+BuildRequires: kernel
%endif
%if %{have_iasl}
# For acpi compilation
@@ -1895,6 +1894,7 @@ getent passwd qemu >/dev/null || \
* Fri Sep 4 2020 Daniel P. Berrangé <berrange(a)redhat.com> - 5.1.0-5
- Drop conditions for ppc, ppc64, mips64 and s390 arches
- Fix host qemu binary path for aarch64
+- Re-enable kernel BR for QEMU sanity check
* Thu Sep 3 2020 Daniel P. Berrangé <berrange(a)redhat.com> - 5.1.0-4
- Add btrfs ioctls to linux-user (rhbz #1872918)
commit 458e07e8d7d455559d8432b04e6c270e4053469b
Author: Daniel P. Berrangé <berrange(a)redhat.com>
Date: Fri Sep 4 10:38:10 2020 +0100
Fix host qemu binary path for aarch64
Signed-off-by: Daniel P. Berrangé <berrange(a)redhat.com>
diff --git a/qemu.spec b/qemu.spec
index ac02483..eda3911 100644
--- a/qemu.spec
+++ b/qemu.spec
@@ -70,7 +70,7 @@
%global hostqemu arm-softmmu/qemu-system-arm
%endif
%ifarch aarch64
-%global hostqemu arm-softmmu/qemu-system-aarch64
+%global hostqemu aarch64-softmmu/qemu-system-aarch64
%endif
%ifarch %{ix86}
%global hostqemu i386-softmmu/qemu-system-i386
@@ -1894,6 +1894,7 @@ getent passwd qemu >/dev/null || \
%changelog
* Fri Sep 4 2020 Daniel P. Berrangé <berrange(a)redhat.com> - 5.1.0-5
- Drop conditions for ppc, ppc64, mips64 and s390 arches
+- Fix host qemu binary path for aarch64
* Thu Sep 3 2020 Daniel P. Berrangé <berrange(a)redhat.com> - 5.1.0-4
- Add btrfs ioctls to linux-user (rhbz #1872918)
commit 3c0f9e810a0b22b439681cedcba6073a20f13d88
Author: Daniel P. Berrangé <berrange(a)redhat.com>
Date: Fri Sep 4 10:04:15 2020 +0100
Drop references to obsolete arches
s390, ppc, ppc64 and mips64 are no longer valid Fedora primary
or alternative architectures.
Signed-off-by: Daniel P. Berrangé <berrange(a)redhat.com>
diff --git a/qemu.spec b/qemu.spec
index 6d5b368..ac02483 100644
--- a/qemu.spec
+++ b/qemu.spec
@@ -33,7 +33,7 @@
# Matches numactl ExcludeArch
%global have_numactl 1
-%ifarch s390 %{arm}
+%ifarch %{arm}
%global have_numactl 0
%endif
@@ -43,7 +43,7 @@
#
# https://bugzilla.redhat.com/show_bug.cgi?id=1332449
%global have_iasl 1
-%ifnarch s390 s390x ppc ppc64
+%ifnarch s390x
%global have_iasl 0
%endif
@@ -170,7 +170,7 @@
Summary: QEMU is a FAST! processor emulator
Name: qemu
Version: 5.1.0
-Release: 4%{?rcrel}%{?dist}
+Release: 5%{?rcrel}%{?dist}
Epoch: 2
License: GPLv2 and BSD and MIT and CC-BY
URL: http://www.qemu.org/
@@ -1002,14 +1002,8 @@ pathfix.py -pni "%{__python3} %{py3_shbang_opts}" scripts/qemu-trace-stap
# Disable LTO since it caused lots of strange assert failures.
%define _lto_cflags %{nil}
-# drop -g flag to prevent memory exhaustion by linker
-%ifarch s390
-%global optflags %(echo %{optflags} | sed 's/-g//')
-sed -i.debug 's/"-g $CFLAGS"/"$CFLAGS"/g' configure
-%endif
-
# OOM killer breaks builds with parallel make on s390(x)
-%ifarch s390 s390x
+%ifarch s390x
%global _smp_mflags %{nil}
%endif
@@ -1198,9 +1192,6 @@ run_configure \
--enable-modules \
--enable-mpath \
%{spiceflag} \
-%ifarch s390 %{mips64}
- --enable-tcg-interpreter \
-%endif
--enable-slirp=system
echo "config-host.mak contents:"
@@ -1399,13 +1390,6 @@ chmod +x %{buildroot}%{_libdir}/qemu/*.so
# Enable this temporarily if tests are broken
%global tests_nofail 0
-# Tests are hanging on s390 as of 2.3.0
-# https://bugzilla.redhat.com/show_bug.cgi?id=1206057
-# Tests seem to be a recurring problem on s390, leave them disabled.
-%ifarch s390
-%global tests_skip 1
-%endif
-
# 2020-08-31: tests passing, but s390x fails due to
# spurious warning breaking an iotest case
# https://lists.gnu.org/archive/html/qemu-devel/2020-08/msg03279.html
@@ -1908,6 +1892,9 @@ getent passwd qemu >/dev/null || \
%changelog
+* Fri Sep 4 2020 Daniel P. Berrangé <berrange(a)redhat.com> - 5.1.0-5
+- Drop conditions for ppc, ppc64, mips64 and s390 arches
+
* Thu Sep 3 2020 Daniel P. Berrangé <berrange(a)redhat.com> - 5.1.0-4
- Add btrfs ioctls to linux-user (rhbz #1872918)
commit dc03f389d339a92a50a6206b62af58ad50e6bd80
Author: Daniel P. Berrangé <berrange(a)redhat.com>
Date: Thu Sep 3 11:02:04 2020 +0100
Add btrfs ioctls to linux-user (rhbz #1872918)
Signed-off-by: Daniel P. Berrangé <berrange(a)redhat.com>
diff --git a/0001-linux-user-fix-implicit-conversion-from-enumeration-.patch b/0001-linux-user-fix-implicit-conversion-from-enumeration-.patch
new file mode 100644
index 0000000..3e53419
--- /dev/null
+++ b/0001-linux-user-fix-implicit-conversion-from-enumeration-.patch
@@ -0,0 +1,35 @@
+From 44716867275c9a5cdead2d70e6187b5af4087f07 Mon Sep 17 00:00:00 2001
+From: Laurent Vivier <laurent(a)vivier.eu>
+Date: Thu, 3 Sep 2020 01:26:53 +0200
+Subject: [PATCH 1/9] linux-user: fix implicit conversion from enumeration type
+ error
+
+MK_ARRAY(type,size) is used to fill the field_types buffer, and if the
+"size" parameter is an enum type, clang [-Werror,-Wenum-conversion] reports
+an error when it is assigned to field_types which is also an enum, argtypes.
+
+To avoid that, convert "size" to "int" in MK_ARRAY(). "int" is the type
+used for the size evaluation in thunk_type_size().
+
+Signed-off-by: Laurent Vivier <laurent(a)vivier.eu>
+Message-Id: <20200902125752.1033524-1-laurent(a)vivier.eu>
+---
+ include/exec/user/thunk.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/include/exec/user/thunk.h b/include/exec/user/thunk.h
+index 7992475c9f..2099482cff 100644
+--- a/include/exec/user/thunk.h
++++ b/include/exec/user/thunk.h
+@@ -42,7 +42,7 @@ typedef enum argtype {
+ } argtype;
+
+ #define MK_PTR(type) TYPE_PTR, type
+-#define MK_ARRAY(type, size) TYPE_ARRAY, size, type
++#define MK_ARRAY(type, size) TYPE_ARRAY, (int)(size), type
+ #define MK_STRUCT(id) TYPE_STRUCT, id
+
+ #define THUNK_TARGET 0
+--
+2.26.2
+
diff --git a/0002-linux-user-Add-support-for-a-group-of-btrfs-ioctls-u.patch b/0002-linux-user-Add-support-for-a-group-of-btrfs-ioctls-u.patch
new file mode 100644
index 0000000..e8106ed
--- /dev/null
+++ b/0002-linux-user-Add-support-for-a-group-of-btrfs-ioctls-u.patch
@@ -0,0 +1,264 @@
+From e0eab99255d34c9dbaac7b73a1a2a79f823a7da9 Mon Sep 17 00:00:00 2001
+From: Filip Bozuta <Filip.Bozuta(a)syrmia.com>
+Date: Thu, 3 Sep 2020 01:26:54 +0200
+Subject: [PATCH 2/9] linux-user: Add support for a group of btrfs ioctls used
+ for subvolumes
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This patch implements functionality of following ioctls:
+
+BTRFS_IOC_SUBVOL_CREATE - Creating a btrfs subvolume
+
+ Create a btrfs subvolume. The subvolume is created using the ioctl's
+ third argument which represents a pointer to a following structure
+ type:
+
+ struct btrfs_ioctl_vol_args {
+ __s64 fd;
+ char name[BTRFS_PATH_NAME_MAX + 1];
+ };
+
+ Before calling this ioctl, the fields of this structure should be filled
+ with aproppriate values. The fd field represents the file descriptor
+ value of the subvolume and the name field represents the subvolume
+ path.
+
+BTRFS_IOC_SUBVOL_GETFLAGS - Getting subvolume flags
+
+ Read the flags of the btrfs subvolume. The flags are read using
+ the ioctl's third argument that is a pointer of __u64 (unsigned long).
+ The third argument represents a bit mask that can be composed of following
+ values:
+ BTRFS_SUBVOL_RDONLY (1ULL << 1)
+ BTRFS_SUBVOL_QGROUP_INHERIT (1ULL << 2)
+ BTRFS_DEVICE_SPEC_BY_ID (1ULL << 3)
+ BTRFS_SUBVOL_SPEC_BY_ID (1ULL << 4)
+
+BTRFS_IOC_SUBVOL_SETFLAGS - Setting subvolume flags
+
+ Set the flags of the btrfs subvolume. The flags are set using the
+ ioctl's third argument that is a pointer of __u64 (unsigned long).
+ The third argument represents a bit mask that can be composed of same
+ values as in the case of previous ioctl (BTRFS_IOC_SUBVOL_GETFLAGS).
+
+BTRFS_IOC_SUBVOL_GETINFO - Getting subvolume information
+
+ Read information about the subvolume. The subvolume information is
+ returned in the ioctl's third argument which represents a pointer to
+ a following structure type:
+
+ struct btrfs_ioctl_get_subvol_info_args {
+ /* Id of this subvolume */
+ __u64 treeid;
+
+ /* Name of this subvolume, used to get the real name at mount point */
+ char name[BTRFS_VOL_NAME_MAX + 1];
+
+ /*
+ * Id of the subvolume which contains this subvolume.
+ * Zero for top-level subvolume or a deleted subvolume.
+ */
+ __u64 parent_id;
+
+ /*
+ * Inode number of the directory which contains this subvolume.
+ * Zero for top-level subvolume or a deleted subvolume
+ */
+ __u64 dirid;
+
+ /* Latest transaction id of this subvolume */
+ __u64 generation;
+
+ /* Flags of this subvolume */
+ __u64 flags;
+
+ /* UUID of this subvolume */
+ __u8 uuid[BTRFS_UUID_SIZE];
+
+ /*
+ * UUID of the subvolume of which this subvolume is a snapshot.
+ * All zero for a non-snapshot subvolume.
+ */
+ __u8 parent_uuid[BTRFS_UUID_SIZE];
+
+ /*
+ * UUID of the subvolume from which this subvolume was received.
+ * All zero for non-received subvolume.
+ */
+ __u8 received_uuid[BTRFS_UUID_SIZE];
+
+ /* Transaction id indicating when change/create/send/receive happened */
+ __u64 ctransid;
+ __u64 otransid;
+ __u64 stransid;
+ __u64 rtransid;
+ /* Time corresponding to c/o/s/rtransid */
+ struct btrfs_ioctl_timespec ctime;
+ struct btrfs_ioctl_timespec otime;
+ struct btrfs_ioctl_timespec stime;
+ struct btrfs_ioctl_timespec rtime;
+
+ /* Must be zero */
+ __u64 reserved[8];
+ };
+
+ All of the fields of this structure are filled after the ioctl call.
+
+Implementation notes:
+
+ Ioctls BTRFS_IOC_SUBVOL_CREATE and BTRFS_IOC_SUBVOL_GETINFO have structure
+ types as third arguments. That is the reason why a corresponding definition
+ are added in file 'linux-user/syscall_types.h'.
+
+ The line '#include <linux/btrfs.h>' is added in file 'linux-user/syscall.c' to
+ recognise preprocessor definitions for these ioctls. Since the file "linux/btrfs.h"
+ was added in the kernel version 3.9, it is enwrapped in an #ifdef statement
+ with parameter CONFIG_BTRFS which is defined in 'configure' if the
+ header file is present.
+
+Signed-off-by: Filip Bozuta <Filip.Bozuta(a)syrmia.com>
+Tested-by: Daniel P. Berrangé <berrange(a)redhat.com>
+Message-Id: <20200823195014.116226-2-Filip.Bozuta(a)syrmia.com>
+Signed-off-by: Laurent Vivier <laurent(a)vivier.eu>
+---
+ configure | 9 +++++++++
+ linux-user/ioctls.h | 15 +++++++++++++++
+ linux-user/syscall.c | 3 +++
+ linux-user/syscall_defs.h | 8 ++++++++
+ linux-user/syscall_types.h | 32 ++++++++++++++++++++++++++++++++
+ 5 files changed, 67 insertions(+)
+
+diff --git a/configure b/configure
+index 2acc4d1465..1cba4e0b80 100755
+--- a/configure
++++ b/configure
+@@ -5079,6 +5079,12 @@ if check_include sys/kcov.h ; then
+ kcov=yes
+ fi
+
++# check for btrfs filesystem support (kernel must be 3.9+)
++btrfs=no
++if check_include linux/btrfs.h ; then
++ btrfs=yes
++fi
++
+ # If we're making warnings fatal, apply this to Sphinx runs as well
+ sphinx_werror=""
+ if test "$werror" = "yes"; then
+@@ -7330,6 +7336,9 @@ fi
+ if test "$kcov" = "yes" ; then
+ echo "CONFIG_KCOV=y" >> $config_host_mak
+ fi
++if test "$btrfs" = "yes" ; then
++ echo "CONFIG_BTRFS=y" >> $config_host_mak
++fi
+ if test "$inotify" = "yes" ; then
+ echo "CONFIG_INOTIFY=y" >> $config_host_mak
+ fi
+diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h
+index 0713ae1311..12d1444224 100644
+--- a/linux-user/ioctls.h
++++ b/linux-user/ioctls.h
+@@ -174,6 +174,21 @@
+ IOCTL(FS_IOC32_GETVERSION, IOC_R, MK_PTR(TYPE_INT))
+ IOCTL(FS_IOC32_SETVERSION, IOC_W, MK_PTR(TYPE_INT))
+
++#ifdef BTRFS_IOC_SUBVOL_CREATE
++ IOCTL(BTRFS_IOC_SUBVOL_CREATE, IOC_W,
++ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_vol_args)))
++#endif
++#ifdef BTRFS_IOC_SUBVOL_GETFLAGS
++ IOCTL(BTRFS_IOC_SUBVOL_GETFLAGS, IOC_R, MK_PTR(TYPE_ULONGLONG))
++#endif
++#ifdef BTRFS_IOC_SUBVOL_SETFLAGS
++ IOCTL(BTRFS_IOC_SUBVOL_SETFLAGS, IOC_W, MK_PTR(TYPE_ULONGLONG))
++#endif
++#ifdef BTRFS_IOC_GET_SUBVOL_INFO
++ IOCTL(BTRFS_IOC_GET_SUBVOL_INFO, IOC_R,
++ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_get_subvol_info_args)))
++#endif
++
+ #ifdef CONFIG_USBFS
+ /* USB ioctls */
+ IOCTL(USBDEVFS_CONTROL, IOC_RW,
+diff --git a/linux-user/syscall.c b/linux-user/syscall.c
+index 945fc25279..36777c91b0 100644
+--- a/linux-user/syscall.c
++++ b/linux-user/syscall.c
+@@ -112,6 +112,9 @@
+ #include <linux/if_alg.h>
+ #include <linux/rtc.h>
+ #include <sound/asound.h>
++#ifdef CONFIG_BTRFS
++#include <linux/btrfs.h>
++#endif
+ #ifdef HAVE_DRM_H
+ #include <libdrm/drm.h>
+ #endif
+diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
+index 3c261cff0e..2757956dfa 100644
+--- a/linux-user/syscall_defs.h
++++ b/linux-user/syscall_defs.h
+@@ -967,6 +967,14 @@ struct target_rtc_pll_info {
+ #define TARGET_FS_IOC32_GETVERSION TARGET_IOR('v', 1, int)
+ #define TARGET_FS_IOC32_SETVERSION TARGET_IOW('v', 2, int)
+
++/* btrfs ioctls */
++#define TARGET_BTRFS_IOC_SUBVOL_CREATE TARGET_IOWU(BTRFS_IOCTL_MAGIC, 14)
++#define TARGET_BTRFS_IOC_SUBVOL_GETFLAGS TARGET_IOR(BTRFS_IOCTL_MAGIC, 25,\
++ abi_ullong)
++#define TARGET_BTRFS_IOC_SUBVOL_SETFLAGS TARGET_IOW(BTRFS_IOCTL_MAGIC, 26,\
++ abi_ullong)
++#define TARGET_BTRFS_IOC_GET_SUBVOL_INFO TARGET_IORU(BTRFS_IOCTL_MAGIC, 60)
++
+ /* usb ioctls */
+ #define TARGET_USBDEVFS_CONTROL TARGET_IOWRU('U', 0)
+ #define TARGET_USBDEVFS_BULK TARGET_IOWRU('U', 2)
+diff --git a/linux-user/syscall_types.h b/linux-user/syscall_types.h
+index 3f1f033464..db61dbc1b3 100644
+--- a/linux-user/syscall_types.h
++++ b/linux-user/syscall_types.h
+@@ -354,6 +354,38 @@ STRUCT(blkpg_partition,
+ MK_ARRAY(TYPE_CHAR, BLKPG_DEVNAMELTH), /* devname */
+ MK_ARRAY(TYPE_CHAR, BLKPG_VOLNAMELTH)) /* volname */
+
++#ifdef BTRFS_IOC_SUBVOL_CREATE
++STRUCT(btrfs_ioctl_vol_args,
++ TYPE_LONGLONG, /* fd */
++ MK_ARRAY(TYPE_CHAR, BTRFS_PATH_NAME_MAX + 1)) /* name */
++#endif
++
++#ifdef BTRFS_IOC_GET_SUBVOL_INFO
++STRUCT(btrfs_ioctl_timespec,
++ TYPE_ULONGLONG, /* sec */
++ TYPE_INT) /* nsec */
++
++STRUCT(btrfs_ioctl_get_subvol_info_args,
++ TYPE_ULONGLONG, /* treeid */
++ MK_ARRAY(TYPE_CHAR, BTRFS_VOL_NAME_MAX + 1),
++ TYPE_ULONGLONG, /* parentid */
++ TYPE_ULONGLONG, /* dirid */
++ TYPE_ULONGLONG, /* generation */
++ TYPE_ULONGLONG, /* flags */
++ MK_ARRAY(TYPE_CHAR, BTRFS_UUID_SIZE), /* uuid */
++ MK_ARRAY(TYPE_CHAR, BTRFS_UUID_SIZE), /* parent_uuid */
++ MK_ARRAY(TYPE_CHAR, BTRFS_UUID_SIZE), /* received_uuid */
++ TYPE_ULONGLONG, /* ctransid */
++ TYPE_ULONGLONG, /* otransid */
++ TYPE_ULONGLONG, /* stransid */
++ TYPE_ULONGLONG, /* rtransid */
++ MK_STRUCT(STRUCT_btrfs_ioctl_timespec), /* ctime */
++ MK_STRUCT(STRUCT_btrfs_ioctl_timespec), /* otime */
++ MK_STRUCT(STRUCT_btrfs_ioctl_timespec), /* stime */
++ MK_STRUCT(STRUCT_btrfs_ioctl_timespec), /* rtime */
++ MK_ARRAY(TYPE_ULONGLONG, 8)) /* reserved */
++#endif
++
+ STRUCT(rtc_time,
+ TYPE_INT, /* tm_sec */
+ TYPE_INT, /* tm_min */
+--
+2.26.2
+
diff --git a/0003-linux-user-Add-support-for-a-group-of-btrfs-ioctls-u.patch b/0003-linux-user-Add-support-for-a-group-of-btrfs-ioctls-u.patch
new file mode 100644
index 0000000..2a6a230
--- /dev/null
+++ b/0003-linux-user-Add-support-for-a-group-of-btrfs-ioctls-u.patch
@@ -0,0 +1,98 @@
+From 40fdd783ec707e61c285e081816bd2df54dfede4 Mon Sep 17 00:00:00 2001
+From: Filip Bozuta <Filip.Bozuta(a)syrmia.com>
+Date: Thu, 3 Sep 2020 01:26:55 +0200
+Subject: [PATCH 3/9] linux-user: Add support for a group of btrfs ioctls used
+ for snapshots
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This patch implements functionality for following ioctls:
+
+BTRFS_IOC_SNAP_CREATE - Creating a subvolume snapshot
+
+ Create a snapshot of a btrfs subvolume. The snapshot is created using the
+ ioctl's third argument that is a pointer to a 'struct btrfs_ioctl_vol_args'
+ (which was mentioned in the previous patch). Before calling this ioctl,
+ the fields of the structure should be filled with aproppriate values for
+ the file descriptor and path of the subvolume for which the snapshot is to
+ be created.
+
+BTRFS_IOC_SNAP_DESTROY - Removing a subvolume snapshot
+
+ Delete a snapshot of a btrfs subvolume. The snapshot is deleted using the
+ ioctl's third argument that is a pointer to a 'struct btrfs_ioctl_vol_args'
+ (which was mentioned in the previous patch). Before calling this ioctl,
+ the fields of the structure should be filled with aproppriate values for
+ the file descriptor and path of the subvolume for which the snapshot is to
+ be deleted.
+
+Implementation notes:
+
+ Since the thunk type 'struct btrfs_ioctl_vol_args' is defined in the
+ previous patch, the implementation for these ioctls was straightforward.
+
+Signed-off-by: Filip Bozuta <Filip.Bozuta(a)syrmia.com>
+Tested-by: Daniel P. Berrangé <berrange(a)redhat.com>
+Message-Id: <20200823195014.116226-3-Filip.Bozuta(a)syrmia.com>
+Signed-off-by: Laurent Vivier <laurent(a)vivier.eu>
+---
+ linux-user/ioctls.h | 8 ++++++++
+ linux-user/syscall_defs.h | 2 ++
+ linux-user/syscall_types.h | 3 ++-
+ 3 files changed, 12 insertions(+), 1 deletion(-)
+
+diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h
+index 12d1444224..f33a99f8b6 100644
+--- a/linux-user/ioctls.h
++++ b/linux-user/ioctls.h
+@@ -174,10 +174,18 @@
+ IOCTL(FS_IOC32_GETVERSION, IOC_R, MK_PTR(TYPE_INT))
+ IOCTL(FS_IOC32_SETVERSION, IOC_W, MK_PTR(TYPE_INT))
+
++#ifdef BTRFS_IOC_SNAP_CREATE
++ IOCTL(BTRFS_IOC_SNAP_CREATE, IOC_W,
++ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_vol_args)))
++#endif
+ #ifdef BTRFS_IOC_SUBVOL_CREATE
+ IOCTL(BTRFS_IOC_SUBVOL_CREATE, IOC_W,
+ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_vol_args)))
+ #endif
++#ifdef BTRFS_IOC_SNAP_DESTROY
++ IOCTL(BTRFS_IOC_SNAP_DESTROY, IOC_W,
++ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_vol_args)))
++#endif
+ #ifdef BTRFS_IOC_SUBVOL_GETFLAGS
+ IOCTL(BTRFS_IOC_SUBVOL_GETFLAGS, IOC_R, MK_PTR(TYPE_ULONGLONG))
+ #endif
+diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
+index 2757956dfa..a945e12547 100644
+--- a/linux-user/syscall_defs.h
++++ b/linux-user/syscall_defs.h
+@@ -968,7 +968,9 @@ struct target_rtc_pll_info {
+ #define TARGET_FS_IOC32_SETVERSION TARGET_IOW('v', 2, int)
+
+ /* btrfs ioctls */
++#define TARGET_BTRFS_IOC_SNAP_CREATE TARGET_IOWU(BTRFS_IOCTL_MAGIC, 1)
+ #define TARGET_BTRFS_IOC_SUBVOL_CREATE TARGET_IOWU(BTRFS_IOCTL_MAGIC, 14)
++#define TARGET_BTRFS_IOC_SNAP_DESTROY TARGET_IOWU(BTRFS_IOCTL_MAGIC, 15)
+ #define TARGET_BTRFS_IOC_SUBVOL_GETFLAGS TARGET_IOR(BTRFS_IOCTL_MAGIC, 25,\
+ abi_ullong)
+ #define TARGET_BTRFS_IOC_SUBVOL_SETFLAGS TARGET_IOW(BTRFS_IOCTL_MAGIC, 26,\
+diff --git a/linux-user/syscall_types.h b/linux-user/syscall_types.h
+index db61dbc1b3..038cd7869b 100644
+--- a/linux-user/syscall_types.h
++++ b/linux-user/syscall_types.h
+@@ -354,7 +354,8 @@ STRUCT(blkpg_partition,
+ MK_ARRAY(TYPE_CHAR, BLKPG_DEVNAMELTH), /* devname */
+ MK_ARRAY(TYPE_CHAR, BLKPG_VOLNAMELTH)) /* volname */
+
+-#ifdef BTRFS_IOC_SUBVOL_CREATE
++#if defined(BTRFS_IOC_SUBVOL_CREATE) || defined(BTRFS_IOC_SNAP_CREATE) || \
++ defined(BTRFS_IOC_SNAP_DESTROY)
+ STRUCT(btrfs_ioctl_vol_args,
+ TYPE_LONGLONG, /* fd */
+ MK_ARRAY(TYPE_CHAR, BTRFS_PATH_NAME_MAX + 1)) /* name */
+--
+2.26.2
+
diff --git a/0004-linux-user-Add-support-for-btrfs-ioctls-used-to-mani.patch b/0004-linux-user-Add-support-for-btrfs-ioctls-used-to-mani.patch
new file mode 100644
index 0000000..a6a0095
--- /dev/null
+++ b/0004-linux-user-Add-support-for-btrfs-ioctls-used-to-mani.patch
@@ -0,0 +1,222 @@
+From ead1cdc1e4bb9fa4d09ca4d8af94c2687e7f5d36 Mon Sep 17 00:00:00 2001
+From: Filip Bozuta <Filip.Bozuta(a)syrmia.com>
+Date: Thu, 3 Sep 2020 01:26:56 +0200
+Subject: [PATCH 4/9] linux-user: Add support for btrfs ioctls used to
+ manipulate with devices
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This patch implements functionality for following ioctls:
+
+BTRFS_IOC_SCAN_DEV - Scanning device for a btrfs filesystem
+
+ Scan a device for a btrfs filesystem. The device that is to
+ be scanned is passed in the ioctl's third argument which
+ represents a pointer to a 'struct ioc_vol_args' (which was
+ mentioned in a previous patch). Before calling this ioctl,
+ the name field of this structure should be filled with the
+ aproppriate name value which represents a path for the device.
+ If the device contains a btrfs filesystem, the ioctl returns 0,
+ otherwise a negative value is returned.
+
+BTRFS_IOC_ADD_DEV - Adding a device to a btrfs filesystem
+
+ Add a device to a btrfs filesystem. The device that is to be
+ added is passed in the ioctl's third argument which represents
+ a pointer to a 'struct ioc_vol_args' (which was mentioned in
+ a previous patch). Before calling this ioctl, the name field of
+ this structure should be filled with the aproppriate name value
+ which represents a path for the device.
+
+BTRFS_IOC_RM_DEV - Removing a device from a btrfs filesystem
+
+ Remove a device from a btrfs filesystem. The device that is to be
+ removed is passed in the ioctl's third argument which represents
+ a pointer to a 'struct ioc_vol_args' (which was mentioned in
+ a previous patch). Before calling this ioctl, the name field of
+ this structure should be filled with the aproppriate name value
+ which represents a path for the device.
+
+BTRFS_IOC_DEV_INFO - Getting information about a device
+
+ Obtain information for device in a btrfs filesystem. The information
+ is gathered in the ioctl's third argument which represents a pointer
+ to a following structure type:
+
+ struct btrfs_ioctl_dev_info_args {
+ __u64 devid; /* in/out */
+ __u8 uuid[BTRFS_UUID_SIZE]; /* in/out */
+ __u64 bytes_used; /* out */
+ __u64 total_bytes; /* out */
+ __u64 unused[379]; /* pad to 4k */
+ __u8 path[BTRFS_DEVICE_PATH_NAME_MAX]; /* out */
+ };
+
+ Before calling this ioctl, field "devid" should be set with the id value
+ for the device for which the information is to be obtained. If this field
+ is not aproppriately set, the errno ENODEV ("No such device") is returned.
+
+BTRFS_IOC_GET_DEV_STATS - Getting device statistics
+
+ Obtain stats informatin for device in a btrfs filesystem. The information
+ is gathered in the ioctl's third argument which represents a pointer to
+ a following structure type:
+
+ struct btrfs_ioctl_get_dev_stats {
+ __u64 devid; /* in */
+ __u64 nr_items; /* in/out */
+ __u64 flags; /* in/out */
+
+ /* out values: */
+ __u64 values[BTRFS_DEV_STAT_VALUES_MAX];
+
+ /*
+ * This pads the struct to 1032 bytes. It was originally meant to pad to
+ * 1024 bytes, but when adding the flags field, the padding calculation
+ * was not adjusted.
+ */
+ __u64 unused[128 - 2 - BTRFS_DEV_STAT_VALUES_MAX];
+ };
+
+ Before calling this ioctl, field "devid" should be set with the id value
+ for the device for which the information is to be obtained. If this field
+ is not aproppriately set, the errno ENODEV ("No such device") is returned.
+
+BTRFS_IOC_FORGET_DEV - Remove unmounted devices
+
+ Search and remove all stale devices (devices which are not mounted).
+ The third ioctl argument is a pointer to a 'struct btrfs_ioctl_vol_args'.
+ The ioctl call will release all unmounted devices which match the path
+ which is specified in the "name" field of the structure. If an empty
+ path ("") is specified, all unmounted devices will be released.
+
+Implementation notes:
+
+ Ioctls BTRFS_IOC_DEV_INFO and BTRFS_IOC_GET_DEV_STATS use types
+ 'struct btrfs_ioctl_dev_info_args' and ' struct btrfs_ioctl_get_dev_stats'
+ as third argument types. That is the reason why corresponding structure
+ definitions were added in file 'linux-user/syscall_types.h'.
+ Since the thunk type for 'struct ioc_vol_args' was already added in a
+ previous patch, the rest of the implementation was straightforward.
+
+Signed-off-by: Filip Bozuta <Filip.Bozuta(a)syrmia.com>
+Tested-by: Daniel P. Berrangé <berrange(a)redhat.com>
+Message-Id: <20200823195014.116226-4-Filip.Bozuta(a)syrmia.com>
+Signed-off-by: Laurent Vivier <laurent(a)vivier.eu>
+---
+ linux-user/ioctls.h | 24 ++++++++++++++++++++++++
+ linux-user/syscall_defs.h | 6 ++++++
+ linux-user/syscall_types.h | 24 +++++++++++++++++++++++-
+ 3 files changed, 53 insertions(+), 1 deletion(-)
+
+diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h
+index f33a99f8b6..55a6cbeca5 100644
+--- a/linux-user/ioctls.h
++++ b/linux-user/ioctls.h
+@@ -178,6 +178,22 @@
+ IOCTL(BTRFS_IOC_SNAP_CREATE, IOC_W,
+ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_vol_args)))
+ #endif
++#ifdef BTRFS_IOC_SCAN_DEV
++ IOCTL(BTRFS_IOC_SCAN_DEV, IOC_W,
++ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_vol_args)))
++#endif
++#ifdef BTRFS_IOC_FORGET_DEV
++ IOCTL(BTRFS_IOC_FORGET_DEV, IOC_W,
++ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_vol_args)))
++#endif
++#ifdef BTRFS_IOC_ADD_DEV
++ IOCTL(BTRFS_IOC_ADD_DEV, IOC_W,
++ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_vol_args)))
++#endif
++#ifdef BTRFS_IOC_RM_DEV
++ IOCTL(BTRFS_IOC_RM_DEV, IOC_W,
++ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_vol_args)))
++#endif
+ #ifdef BTRFS_IOC_SUBVOL_CREATE
+ IOCTL(BTRFS_IOC_SUBVOL_CREATE, IOC_W,
+ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_vol_args)))
+@@ -192,6 +208,14 @@
+ #ifdef BTRFS_IOC_SUBVOL_SETFLAGS
+ IOCTL(BTRFS_IOC_SUBVOL_SETFLAGS, IOC_W, MK_PTR(TYPE_ULONGLONG))
+ #endif
++#ifdef BTRFS_IOC_DEV_INFO
++ IOCTL(BTRFS_IOC_DEV_INFO, IOC_RW,
++ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_dev_info_args)))
++#endif
++#ifdef BTRFS_IOC_GET_DEV_STATS
++ IOCTL(BTRFS_IOC_GET_DEV_STATS, IOC_RW,
++ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_get_dev_stats)))
++#endif
+ #ifdef BTRFS_IOC_GET_SUBVOL_INFO
+ IOCTL(BTRFS_IOC_GET_SUBVOL_INFO, IOC_R,
+ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_get_subvol_info_args)))
+diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
+index a945e12547..4c7bfa0391 100644
+--- a/linux-user/syscall_defs.h
++++ b/linux-user/syscall_defs.h
+@@ -969,12 +969,18 @@ struct target_rtc_pll_info {
+
+ /* btrfs ioctls */
+ #define TARGET_BTRFS_IOC_SNAP_CREATE TARGET_IOWU(BTRFS_IOCTL_MAGIC, 1)
++#define TARGET_BTRFS_IOC_SCAN_DEV TARGET_IOWU(BTRFS_IOCTL_MAGIC, 4)
++#define TARGET_BTRFS_IOC_FORGET_DEV TARGET_IOWU(BTRFS_IOCTL_MAGIC, 5)
++#define TARGET_BTRFS_IOC_ADD_DEV TARGET_IOWU(BTRFS_IOCTL_MAGIC, 10)
++#define TARGET_BTRFS_IOC_RM_DEV TARGET_IOWU(BTRFS_IOCTL_MAGIC, 11)
+ #define TARGET_BTRFS_IOC_SUBVOL_CREATE TARGET_IOWU(BTRFS_IOCTL_MAGIC, 14)
+ #define TARGET_BTRFS_IOC_SNAP_DESTROY TARGET_IOWU(BTRFS_IOCTL_MAGIC, 15)
+ #define TARGET_BTRFS_IOC_SUBVOL_GETFLAGS TARGET_IOR(BTRFS_IOCTL_MAGIC, 25,\
+ abi_ullong)
+ #define TARGET_BTRFS_IOC_SUBVOL_SETFLAGS TARGET_IOW(BTRFS_IOCTL_MAGIC, 26,\
+ abi_ullong)
++#define TARGET_BTRFS_IOC_DEV_INFO TARGET_IOWRU(BTRFS_IOCTL_MAGIC, 30)
++#define TARGET_BTRFS_IOC_GET_DEV_STATS TARGET_IOWRU(BTRFS_IOCTL_MAGIC, 52)
+ #define TARGET_BTRFS_IOC_GET_SUBVOL_INFO TARGET_IORU(BTRFS_IOCTL_MAGIC, 60)
+
+ /* usb ioctls */
+diff --git a/linux-user/syscall_types.h b/linux-user/syscall_types.h
+index 038cd7869b..ea6898979b 100644
+--- a/linux-user/syscall_types.h
++++ b/linux-user/syscall_types.h
+@@ -355,7 +355,9 @@ STRUCT(blkpg_partition,
+ MK_ARRAY(TYPE_CHAR, BLKPG_VOLNAMELTH)) /* volname */
+
+ #if defined(BTRFS_IOC_SUBVOL_CREATE) || defined(BTRFS_IOC_SNAP_CREATE) || \
+- defined(BTRFS_IOC_SNAP_DESTROY)
++ defined(BTRFS_IOC_SNAP_DESTROY) || defined(BTRFS_IOC_SCAN_DEV) || \
++ defined(BTRFS_IOC_FORGET_DEV) || defined(BTRFS_IOC_ADD_DEV) || \
++ defined(BTRFS_IOC_RM_DEV) || defined(BTRFS_IOC_DEV_INFO)
+ STRUCT(btrfs_ioctl_vol_args,
+ TYPE_LONGLONG, /* fd */
+ MK_ARRAY(TYPE_CHAR, BTRFS_PATH_NAME_MAX + 1)) /* name */
+@@ -387,6 +389,26 @@ STRUCT(btrfs_ioctl_get_subvol_info_args,
+ MK_ARRAY(TYPE_ULONGLONG, 8)) /* reserved */
+ #endif
+
++#ifdef BTRFS_IOC_DEV_INFO
++STRUCT(btrfs_ioctl_dev_info_args,
++ TYPE_ULONGLONG, /* devid */
++ MK_ARRAY(TYPE_CHAR, BTRFS_UUID_SIZE), /* uuid */
++ TYPE_ULONGLONG, /* bytes_used */
++ TYPE_ULONGLONG, /* total_bytes */
++ MK_ARRAY(TYPE_ULONGLONG, 379), /* unused */
++ MK_ARRAY(TYPE_CHAR, BTRFS_DEVICE_PATH_NAME_MAX)) /* path */
++#endif
++
++#ifdef BTRFS_IOC_GET_DEV_STATS
++STRUCT(btrfs_ioctl_get_dev_stats,
++ TYPE_ULONGLONG, /* devid */
++ TYPE_ULONGLONG, /* nr_items */
++ TYPE_ULONGLONG, /* flags */
++ MK_ARRAY(TYPE_ULONGLONG, BTRFS_DEV_STAT_VALUES_MAX), /* values */
++ MK_ARRAY(TYPE_ULONGLONG,
++ 128 - 2 - BTRFS_DEV_STAT_VALUES_MAX)) /* unused */
++#endif
++
+ STRUCT(rtc_time,
+ TYPE_INT, /* tm_sec */
+ TYPE_INT, /* tm_min */
+--
+2.26.2
+
diff --git a/0005-linux-user-Add-support-for-btrfs-ioctls-used-to-get-.patch b/0005-linux-user-Add-support-for-btrfs-ioctls-used-to-get-.patch
new file mode 100644
index 0000000..cfcd47a
--- /dev/null
+++ b/0005-linux-user-Add-support-for-btrfs-ioctls-used-to-get-.patch
@@ -0,0 +1,120 @@
+From 5793eb73d4d6d37293c6ca95ed85414fcccb9662 Mon Sep 17 00:00:00 2001
+From: Filip Bozuta <Filip.Bozuta(a)syrmia.com>
+Date: Thu, 3 Sep 2020 01:26:57 +0200
+Subject: [PATCH 5/9] linux-user: Add support for btrfs ioctls used to get/set
+ features
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This patch implements functionality for following ioctls:
+
+BTRFS_IOC_GET_FEATURES - Getting feature flags
+
+ Read feature flags for a btrfs filesystem. The feature flags
+ are returned inside the ioctl's third argument which represents
+ a pointer to a following structure type:
+
+ struct btrfs_ioctl_feature_flags {
+ __u64 compat_flags;
+ __u64 compat_ro_flags;
+ __u64 incompat_flags;
+ };
+
+ All of the structure field represent bit masks that can be composed
+ of values which can be found on:
+ https://elixir.bootlin.com/linux/latest/source/fs/btrfs/ctree.h#L282
+
+BTRFS_IOC_SET_FEATURES - Setting feature flags
+
+ Set and clear feature flags for a btrfs filesystem. The feature flags
+ are set using the ioctl's third argument which represents a
+ 'struct btrfs_ioctl_feature_flags[2]' array. The first element of the
+ array represent flags which are to be cleared and the second element of
+ the array represent flags which are to be set. The second element has the
+ priority over the first, which means that if there are matching flags
+ in the elements, they will be set in the filesystem. If the flag values
+ in the third argument aren't correctly set to be composed of the available
+ predefined flag values, errno ENOPERM ("Operation not permitted") is returned.
+
+BTRFS_IOC_GET_SUPPORTED_FEATURES - Getting supported feature flags
+
+ Read supported feature flags for a btrfs filesystem. The supported
+ feature flags are read using the ioctl's third argument which represents
+ a 'struct btrfs_ioctl_feature_flags[3]' array. The first element of this
+ array represents all of the supported flags in the btrfs filesystem.
+ The second element represents flags that can be safely set and third element
+ represent flags that can be safely clearead.
+
+Implementation notes:
+
+ All of the implemented ioctls use 'struct btrfs_ioctl_feature_flags' as
+ third argument. That is the reason why a corresponding defintion was added
+ in file 'linux-user/syscall_types.h'.
+
+Signed-off-by: Filip Bozuta <Filip.Bozuta(a)syrmia.com>
+Tested-by: Daniel P. Berrangé <berrange(a)redhat.com>
+Message-Id: <20200823195014.116226-5-Filip.Bozuta(a)syrmia.com>
+Signed-off-by: Laurent Vivier <laurent(a)vivier.eu>
+---
+ linux-user/ioctls.h | 12 ++++++++++++
+ linux-user/syscall_defs.h | 3 +++
+ linux-user/syscall_types.h | 5 +++++
+ 3 files changed, 20 insertions(+)
+
+diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h
+index 55a6cbeca5..50fae1e33b 100644
+--- a/linux-user/ioctls.h
++++ b/linux-user/ioctls.h
+@@ -216,6 +216,18 @@
+ IOCTL(BTRFS_IOC_GET_DEV_STATS, IOC_RW,
+ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_get_dev_stats)))
+ #endif
++#ifdef BTRFS_IOC_GET_FEATURES
++ IOCTL(BTRFS_IOC_GET_FEATURES, IOC_R,
++ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_feature_flags)))
++#endif
++#ifdef BTRFS_IOC_SET_FEATURES
++ IOCTL(BTRFS_IOC_SET_FEATURES, IOC_W,
++ MK_PTR(MK_ARRAY(MK_STRUCT(STRUCT_btrfs_ioctl_feature_flags), 2)))
++#endif
++#ifdef BTRFS_IOC_GET_SUPPORTED_FEATURES
++ IOCTL(BTRFS_IOC_GET_SUPPORTED_FEATURES, IOC_R,
++ MK_PTR(MK_ARRAY(MK_STRUCT(STRUCT_btrfs_ioctl_feature_flags), 3)))
++#endif
+ #ifdef BTRFS_IOC_GET_SUBVOL_INFO
+ IOCTL(BTRFS_IOC_GET_SUBVOL_INFO, IOC_R,
+ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_get_subvol_info_args)))
+diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
+index 4c7bfa0391..44811fdcbb 100644
+--- a/linux-user/syscall_defs.h
++++ b/linux-user/syscall_defs.h
+@@ -981,6 +981,9 @@ struct target_rtc_pll_info {
+ abi_ullong)
+ #define TARGET_BTRFS_IOC_DEV_INFO TARGET_IOWRU(BTRFS_IOCTL_MAGIC, 30)
+ #define TARGET_BTRFS_IOC_GET_DEV_STATS TARGET_IOWRU(BTRFS_IOCTL_MAGIC, 52)
++#define TARGET_BTRFS_IOC_GET_FEATURES TARGET_IORU(BTRFS_IOCTL_MAGIC, 57)
++#define TARGET_BTRFS_IOC_SET_FEATURES TARGET_IOWU(BTRFS_IOCTL_MAGIC, 57)
++#define TARGET_BTRFS_IOC_GET_SUPPORTED_FEATURES TARGET_IORU(BTRFS_IOCTL_MAGIC, 57)
+ #define TARGET_BTRFS_IOC_GET_SUBVOL_INFO TARGET_IORU(BTRFS_IOCTL_MAGIC, 60)
+
+ /* usb ioctls */
+diff --git a/linux-user/syscall_types.h b/linux-user/syscall_types.h
+index ea6898979b..925054cfd4 100644
+--- a/linux-user/syscall_types.h
++++ b/linux-user/syscall_types.h
+@@ -409,6 +409,11 @@ STRUCT(btrfs_ioctl_get_dev_stats,
+ 128 - 2 - BTRFS_DEV_STAT_VALUES_MAX)) /* unused */
+ #endif
+
++STRUCT(btrfs_ioctl_feature_flags,
++ TYPE_ULONGLONG, /* compat_flags */
++ TYPE_ULONGLONG, /* compat_ro_flags */
++ TYPE_ULONGLONG) /* incompat_flags */
++
+ STRUCT(rtc_time,
+ TYPE_INT, /* tm_sec */
+ TYPE_INT, /* tm_min */
+--
+2.26.2
+
diff --git a/0006-linux-user-Add-support-for-a-group-of-btrfs-inode-io.patch b/0006-linux-user-Add-support-for-a-group-of-btrfs-inode-io.patch
new file mode 100644
index 0000000..a953a23
--- /dev/null
+++ b/0006-linux-user-Add-support-for-a-group-of-btrfs-inode-io.patch
@@ -0,0 +1,236 @@
+From 79116330e3eea392dec9a1f38fddf3449ad0195a Mon Sep 17 00:00:00 2001
+From: Filip Bozuta <Filip.Bozuta(a)syrmia.com>
+Date: Thu, 3 Sep 2020 01:26:58 +0200
+Subject: [PATCH 6/9] linux-user: Add support for a group of btrfs inode ioctls
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This patch implements functionality of following ioctls:
+
+BTRFS_IOC_INO_LOOKUP - Reading tree root id and path
+
+ Read tree root id and path for a given file or directory.
+ The name and tree root id are returned in an ioctl's third
+ argument that represents a pointer to a following type:
+
+ struct btrfs_ioctl_ino_lookup_args {
+ __u64 treeid;
+ __u64 objectid;
+ char name[BTRFS_INO_LOOKUP_PATH_MAX];
+ };
+
+ Before calling this ioctl, field 'objectid' should be filled
+ with the object id value for which the tree id and path are
+ to be read. Value 'BTRFS_FIRST_FREE_OBJECTID' represents the
+ object id for the first available btrfs object (directory or
+ file).
+
+BTRFS_IOC_INO_PATHS - Reading paths to all files
+
+ Read path to all files with a certain inode number. The paths
+ are returned in the ioctl's third argument which represents
+ a pointer to a following type:
+
+ struct btrfs_ioctl_ino_path_args {
+ __u64 inum; /* in */
+ __u64 size; /* in */
+ __u64 reserved[4];
+ /* struct btrfs_data_container *fspath; out */
+ __u64 fspath; /* out */
+ };
+
+ Before calling this ioctl, the 'inum' and 'size' field should
+ be filled with the aproppriate inode number and size of the
+ directory where file paths should be looked for. For now, the
+ paths are returned in an '__u64' (unsigned long long) value
+ 'fspath'.
+
+BTRFS_IOC_LOGICAL_INO - Reading inode numbers
+
+ Read inode numbers for files on a certain logical adress. The
+ inode numbers are returned in the ioctl's third argument which
+ represents a pointer to a following type:
+
+ struct btrfs_ioctl_logical_ino_args {
+ __u64 logical; /* in */
+ __u64 size; /* in */
+ __u64 reserved[3]; /* must be 0 for now */
+ __u64 flags; /* in, v2 only */
+ /* struct btrfs_data_container *inodes; out */
+ __u64 inodes;
+ };
+
+ Before calling this ioctl, the 'logical' and 'size' field should
+ be filled with the aproppriate logical adress and size of where
+ the inode numbers of files should be looked for. For now, the
+ inode numbers are returned in an '__u64' (unsigned long long)
+ value 'inodes'.
+
+BTRFS_IOC_LOGICAL_INO_V2 - Reading inode numbers
+
+ Same as the above mentioned ioctl except that it allows passing
+ a flags 'BTRFS_LOGICAL_INO_ARGS_IGNORE_OFFSET'.
+
+BTRFS_IOC_INO_LOOKUP_USER - Reading subvolume name and path
+
+ Read name and path of a subvolume. The tree root id and
+ path are read in an ioctl's third argument which represents a
+ pointer to a following type:
+
+ struct btrfs_ioctl_ino_lookup_user_args {
+ /* in, inode number containing the subvolume of 'subvolid' */
+ __u64 dirid;
+ /* in */
+ __u64 treeid;
+ /* out, name of the subvolume of 'treeid' */
+ char name[BTRFS_VOL_NAME_MAX + 1];
+ /*
+ * out, constructed path from the directory with which the ioctl is
+ * called to dirid
+ */
+ char path[BTRFS_INO_LOOKUP_USER_PATH_MAX];
+ };
+
+ Before calling this ioctl, the 'dirid' and 'treeid' field should
+ be filled with aproppriate values which represent the inode number
+ of the directory that contains the subvolume and treeid of the
+ subvolume.
+
+Implementation notes:
+
+ All of the ioctls in this patch use structure types as third arguments.
+ That is the reason why aproppriate thunk definitions were added in file
+ 'syscall_types.h'.
+
+Signed-off-by: Filip Bozuta <Filip.Bozuta(a)syrmia.com>
+Tested-by: Daniel P. Berrangé <berrange(a)redhat.com>
+Message-Id: <20200823195014.116226-6-Filip.Bozuta(a)syrmia.com>
+Signed-off-by: Laurent Vivier <laurent(a)vivier.eu>
+---
+ linux-user/ioctls.h | 20 ++++++++++++++++++++
+ linux-user/syscall_defs.h | 5 +++++
+ linux-user/syscall_types.h | 32 ++++++++++++++++++++++++++++++++
+ 3 files changed, 57 insertions(+)
+
+diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h
+index 50fae1e33b..169f98f7a3 100644
+--- a/linux-user/ioctls.h
++++ b/linux-user/ioctls.h
+@@ -202,6 +202,10 @@
+ IOCTL(BTRFS_IOC_SNAP_DESTROY, IOC_W,
+ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_vol_args)))
+ #endif
++#ifdef BTRFS_IOC_INO_LOOKUP
++ IOCTL(BTRFS_IOC_INO_LOOKUP, IOC_RW,
++ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_ino_lookup_args)))
++#endif
+ #ifdef BTRFS_IOC_SUBVOL_GETFLAGS
+ IOCTL(BTRFS_IOC_SUBVOL_GETFLAGS, IOC_R, MK_PTR(TYPE_ULONGLONG))
+ #endif
+@@ -212,6 +216,14 @@
+ IOCTL(BTRFS_IOC_DEV_INFO, IOC_RW,
+ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_dev_info_args)))
+ #endif
++#ifdef BTRFS_IOC_INO_PATHS
++ IOCTL(BTRFS_IOC_INO_PATHS, IOC_RW,
++ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_ino_path_args)))
++#endif
++#ifdef BTRFS_IOC_LOGICAL_INO
++ IOCTL(BTRFS_IOC_LOGICAL_INO, IOC_RW,
++ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_logical_ino_args)))
++#endif
+ #ifdef BTRFS_IOC_GET_DEV_STATS
+ IOCTL(BTRFS_IOC_GET_DEV_STATS, IOC_RW,
+ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_get_dev_stats)))
+@@ -228,10 +240,18 @@
+ IOCTL(BTRFS_IOC_GET_SUPPORTED_FEATURES, IOC_R,
+ MK_PTR(MK_ARRAY(MK_STRUCT(STRUCT_btrfs_ioctl_feature_flags), 3)))
+ #endif
++#ifdef BTRFS_IOC_LOGICAL_INO_V2
++ IOCTL(BTRFS_IOC_LOGICAL_INO_V2, IOC_RW,
++ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_logical_ino_args)))
++#endif
+ #ifdef BTRFS_IOC_GET_SUBVOL_INFO
+ IOCTL(BTRFS_IOC_GET_SUBVOL_INFO, IOC_R,
+ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_get_subvol_info_args)))
+ #endif
++#ifdef BTRFS_IOC_INO_LOOKUP_USER
++ IOCTL(BTRFS_IOC_INO_LOOKUP_USER, IOC_RW,
++ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_ino_lookup_user_args)))
++#endif
+
+ #ifdef CONFIG_USBFS
+ /* USB ioctls */
+diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
+index 44811fdcbb..a6a9454b85 100644
+--- a/linux-user/syscall_defs.h
++++ b/linux-user/syscall_defs.h
+@@ -975,16 +975,21 @@ struct target_rtc_pll_info {
+ #define TARGET_BTRFS_IOC_RM_DEV TARGET_IOWU(BTRFS_IOCTL_MAGIC, 11)
+ #define TARGET_BTRFS_IOC_SUBVOL_CREATE TARGET_IOWU(BTRFS_IOCTL_MAGIC, 14)
+ #define TARGET_BTRFS_IOC_SNAP_DESTROY TARGET_IOWU(BTRFS_IOCTL_MAGIC, 15)
++#define TARGET_BTRFS_IOC_INO_LOOKUP TARGET_IOWRU(BTRFS_IOCTL_MAGIC, 18)
+ #define TARGET_BTRFS_IOC_SUBVOL_GETFLAGS TARGET_IOR(BTRFS_IOCTL_MAGIC, 25,\
+ abi_ullong)
+ #define TARGET_BTRFS_IOC_SUBVOL_SETFLAGS TARGET_IOW(BTRFS_IOCTL_MAGIC, 26,\
+ abi_ullong)
+ #define TARGET_BTRFS_IOC_DEV_INFO TARGET_IOWRU(BTRFS_IOCTL_MAGIC, 30)
++#define TARGET_BTRFS_IOC_INO_PATHS TARGET_IOWRU(BTRFS_IOCTL_MAGIC, 35)
++#define TARGET_BTRFS_IOC_LOGICAL_INO TARGET_IOWRU(BTRFS_IOCTL_MAGIC, 36)
+ #define TARGET_BTRFS_IOC_GET_DEV_STATS TARGET_IOWRU(BTRFS_IOCTL_MAGIC, 52)
+ #define TARGET_BTRFS_IOC_GET_FEATURES TARGET_IORU(BTRFS_IOCTL_MAGIC, 57)
+ #define TARGET_BTRFS_IOC_SET_FEATURES TARGET_IOWU(BTRFS_IOCTL_MAGIC, 57)
+ #define TARGET_BTRFS_IOC_GET_SUPPORTED_FEATURES TARGET_IORU(BTRFS_IOCTL_MAGIC, 57)
++#define TARGET_BTRFS_IOC_LOGICAL_INO_V2 TARGET_IOWRU(BTRFS_IOCTL_MAGIC, 59)
+ #define TARGET_BTRFS_IOC_GET_SUBVOL_INFO TARGET_IORU(BTRFS_IOCTL_MAGIC, 60)
++#define TARGET_BTRFS_IOC_INO_LOOKUP_USER TARGET_IOWRU(BTRFS_IOCTL_MAGIC, 62)
+
+ /* usb ioctls */
+ #define TARGET_USBDEVFS_CONTROL TARGET_IOWRU('U', 0)
+diff --git a/linux-user/syscall_types.h b/linux-user/syscall_types.h
+index 925054cfd4..b84e14235f 100644
+--- a/linux-user/syscall_types.h
++++ b/linux-user/syscall_types.h
+@@ -389,6 +389,38 @@ STRUCT(btrfs_ioctl_get_subvol_info_args,
+ MK_ARRAY(TYPE_ULONGLONG, 8)) /* reserved */
+ #endif
+
++#ifdef BTRFS_IOC_INO_LOOKUP
++STRUCT(btrfs_ioctl_ino_lookup_args,
++ TYPE_ULONGLONG, /* treeid */
++ TYPE_ULONGLONG, /* objectid */
++ MK_ARRAY(TYPE_CHAR, BTRFS_INO_LOOKUP_PATH_MAX)) /* name */
++#endif
++
++#ifdef BTRFS_IOC_INO_PATHS
++STRUCT(btrfs_ioctl_ino_path_args,
++ TYPE_ULONGLONG, /* inum */
++ TYPE_ULONGLONG, /* size */
++ MK_ARRAY(TYPE_ULONGLONG, 4), /* reserved */
++ TYPE_ULONGLONG) /* fspath */
++#endif
++
++#if defined(BTRFS_IOC_LOGICAL_INO) || defined(BTRFS_IOC_LOGICAL_INO_V2)
++STRUCT(btrfs_ioctl_logical_ino_args,
++ TYPE_ULONGLONG, /* logical */
++ TYPE_ULONGLONG, /* size */
++ MK_ARRAY(TYPE_ULONGLONG, 3), /* reserved */
++ TYPE_ULONGLONG, /* flags */
++ TYPE_ULONGLONG) /* inodes */
++#endif
++
++#ifdef BTRFS_IOC_INO_LOOKUP_USER
++STRUCT(btrfs_ioctl_ino_lookup_user_args,
++ TYPE_ULONGLONG, /* dirid */
++ TYPE_ULONGLONG, /* treeid */
++ MK_ARRAY(TYPE_CHAR, BTRFS_VOL_NAME_MAX + 1), /* name */
++ MK_ARRAY(TYPE_CHAR, BTRFS_INO_LOOKUP_USER_PATH_MAX)) /* path */
++#endif
++
+ #ifdef BTRFS_IOC_DEV_INFO
+ STRUCT(btrfs_ioctl_dev_info_args,
+ TYPE_ULONGLONG, /* devid */
+--
+2.26.2
+
diff --git a/0007-linux-user-Add-support-for-two-btrfs-ioctls-used-for.patch b/0007-linux-user-Add-support-for-two-btrfs-ioctls-used-for.patch
new file mode 100644
index 0000000..e284817
--- /dev/null
+++ b/0007-linux-user-Add-support-for-two-btrfs-ioctls-used-for.patch
@@ -0,0 +1,132 @@
+From 58252f756d7fb2a8516c0815034c0bded4697852 Mon Sep 17 00:00:00 2001
+From: Filip Bozuta <Filip.Bozuta(a)syrmia.com>
+Date: Thu, 3 Sep 2020 01:26:59 +0200
+Subject: [PATCH 7/9] linux-user: Add support for two btrfs ioctls used for
+ subvolume
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This patch implements functionality for following ioctl:
+
+BTRFS_IOC_DEFAULT_SUBVOL - Setting a default subvolume
+
+ Set a default subvolume for a btrfs filesystem. The third
+ ioctl's argument is a '__u64' (unsigned long long) which
+ represents the id of a subvolume that is to be set as
+ the default.
+
+BTRFS_IOC_GET_SUBVOL_ROOTREF - Getting tree and directory id of subvolumes
+
+ Read tree and directory id of subvolumes from a btrfs
+ filesystem. The tree and directory id's are returned in the
+ ioctl's third argument which represents a pointer to a
+ following type:
+
+ struct btrfs_ioctl_get_subvol_rootref_args {
+ /* in/out, minimum id of rootref's treeid to be searched */
+ __u64 min_treeid;
+
+ /* out */
+ struct {
+ __u64 treeid;
+ __u64 dirid;
+ } rootref[BTRFS_MAX_ROOTREF_BUFFER_NUM];
+
+ /* out, number of found items */
+ __u8 num_items;
+ __u8 align[7];
+ };
+
+ Before calling this ioctl, 'min_treeid' field should be filled
+ with value that represent the minimum value for the tree id.
+
+Implementation notes:
+
+ Ioctl BTRFS_IOC_GET_SUBVOL_ROOTREF uses the above mentioned structure
+ type as third argument. That is the reason why a aproppriate thunk
+ structure definition is added in file 'syscall_types.h'.
+
+Signed-off-by: Filip Bozuta <Filip.Bozuta(a)syrmia.com>
+Tested-by: Daniel P. Berrangé <berrange(a)redhat.com>
+Message-Id: <20200823195014.116226-7-Filip.Bozuta(a)syrmia.com>
+Signed-off-by: Laurent Vivier <laurent(a)vivier.eu>
+---
+ linux-user/ioctls.h | 7 +++++++
+ linux-user/syscall_defs.h | 3 +++
+ linux-user/syscall_types.h | 13 +++++++++++++
+ 3 files changed, 23 insertions(+)
+
+diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h
+index 169f98f7a3..728880b9f3 100644
+--- a/linux-user/ioctls.h
++++ b/linux-user/ioctls.h
+@@ -206,6 +206,9 @@
+ IOCTL(BTRFS_IOC_INO_LOOKUP, IOC_RW,
+ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_ino_lookup_args)))
+ #endif
++#ifdef BTRFS_IOC_DEFAULT_SUBVOL
++ IOCTL(BTRFS_IOC_DEFAULT_SUBVOL, IOC_W, MK_PTR(TYPE_ULONGLONG))
++#endif
+ #ifdef BTRFS_IOC_SUBVOL_GETFLAGS
+ IOCTL(BTRFS_IOC_SUBVOL_GETFLAGS, IOC_R, MK_PTR(TYPE_ULONGLONG))
+ #endif
+@@ -248,6 +251,10 @@
+ IOCTL(BTRFS_IOC_GET_SUBVOL_INFO, IOC_R,
+ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_get_subvol_info_args)))
+ #endif
++#ifdef BTRFS_IOC_GET_SUBVOL_ROOTREF
++ IOCTL(BTRFS_IOC_GET_SUBVOL_ROOTREF, IOC_RW,
++ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_get_subvol_rootref_args)))
++#endif
+ #ifdef BTRFS_IOC_INO_LOOKUP_USER
+ IOCTL(BTRFS_IOC_INO_LOOKUP_USER, IOC_RW,
+ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_ino_lookup_user_args)))
+diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
+index a6a9454b85..1d0bfb5479 100644
+--- a/linux-user/syscall_defs.h
++++ b/linux-user/syscall_defs.h
+@@ -976,6 +976,8 @@ struct target_rtc_pll_info {
+ #define TARGET_BTRFS_IOC_SUBVOL_CREATE TARGET_IOWU(BTRFS_IOCTL_MAGIC, 14)
+ #define TARGET_BTRFS_IOC_SNAP_DESTROY TARGET_IOWU(BTRFS_IOCTL_MAGIC, 15)
+ #define TARGET_BTRFS_IOC_INO_LOOKUP TARGET_IOWRU(BTRFS_IOCTL_MAGIC, 18)
++#define TARGET_BTRFS_IOC_DEFAULT_SUBVOL TARGET_IOW(BTRFS_IOCTL_MAGIC, 19,\
++ abi_ullong)
+ #define TARGET_BTRFS_IOC_SUBVOL_GETFLAGS TARGET_IOR(BTRFS_IOCTL_MAGIC, 25,\
+ abi_ullong)
+ #define TARGET_BTRFS_IOC_SUBVOL_SETFLAGS TARGET_IOW(BTRFS_IOCTL_MAGIC, 26,\
+@@ -989,6 +991,7 @@ struct target_rtc_pll_info {
+ #define TARGET_BTRFS_IOC_GET_SUPPORTED_FEATURES TARGET_IORU(BTRFS_IOCTL_MAGIC, 57)
+ #define TARGET_BTRFS_IOC_LOGICAL_INO_V2 TARGET_IOWRU(BTRFS_IOCTL_MAGIC, 59)
+ #define TARGET_BTRFS_IOC_GET_SUBVOL_INFO TARGET_IORU(BTRFS_IOCTL_MAGIC, 60)
++#define TARGET_BTRFS_IOC_GET_SUBVOL_ROOTREF TARGET_IOWRU(BTRFS_IOCTL_MAGIC, 61)
+ #define TARGET_BTRFS_IOC_INO_LOOKUP_USER TARGET_IOWRU(BTRFS_IOCTL_MAGIC, 62)
+
+ /* usb ioctls */
+diff --git a/linux-user/syscall_types.h b/linux-user/syscall_types.h
+index b84e14235f..5566d101c2 100644
+--- a/linux-user/syscall_types.h
++++ b/linux-user/syscall_types.h
+@@ -431,6 +431,19 @@ STRUCT(btrfs_ioctl_dev_info_args,
+ MK_ARRAY(TYPE_CHAR, BTRFS_DEVICE_PATH_NAME_MAX)) /* path */
+ #endif
+
++#ifdef BTRFS_IOC_GET_SUBVOL_ROOTREF
++STRUCT(rootref,
++ TYPE_ULONGLONG, /* treeid */
++ TYPE_ULONGLONG) /* dirid */
++
++STRUCT(btrfs_ioctl_get_subvol_rootref_args,
++ TYPE_ULONGLONG, /* min_treeid */
++ MK_ARRAY(MK_STRUCT(STRUCT_rootref),
++ BTRFS_MAX_ROOTREF_BUFFER_NUM), /* rootref */
++ TYPE_CHAR, /* num_items */
++ MK_ARRAY(TYPE_CHAR, 7)) /* align */
++#endif
++
+ #ifdef BTRFS_IOC_GET_DEV_STATS
+ STRUCT(btrfs_ioctl_get_dev_stats,
+ TYPE_ULONGLONG, /* devid */
+--
+2.26.2
+
diff --git a/0008-linux-user-Add-support-for-btrfs-ioctls-used-to-mana.patch b/0008-linux-user-Add-support-for-btrfs-ioctls-used-to-mana.patch
new file mode 100644
index 0000000..4871677
--- /dev/null
+++ b/0008-linux-user-Add-support-for-btrfs-ioctls-used-to-mana.patch
@@ -0,0 +1,235 @@
+From d62c16ff35a17743c2a0f8ebfb39f84064afcb3c Mon Sep 17 00:00:00 2001
+From: Filip Bozuta <Filip.Bozuta(a)syrmia.com>
+Date: Thu, 3 Sep 2020 01:27:00 +0200
+Subject: [PATCH 8/9] linux-user: Add support for btrfs ioctls used to manage
+ quota
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This patch implements functionality for following ioctls:
+
+BTRFS_IOC_QUOTA_CTL - Enabling/Disabling quota support
+
+ Enable or disable quota support for a btrfs filesystem. Quota
+ support is enabled or disabled using the ioctls third argument
+ which represents a pointer to a following type:
+
+ struct btrfs_ioctl_quota_ctl_args {
+ __u64 cmd;
+ __u64 status;
+ };
+
+ Before calling this ioctl, the 'cmd' field should be filled
+ with one of the values 'BTRFS_QUOTA_CTL_ENABLE' (enabling quota)
+ 'BTRFS_QUOTA_CTL_DISABLE' (disabling quota).
+
+BTRFS_IOC_QGROUP_CREATE - Creating/Removing a subvolume quota group
+
+ Create or remove a subvolume quota group. The subvolume quota
+ group is created or removed using the ioctl's third argument which
+ represents a pointer to a following type:
+
+ struct btrfs_ioctl_qgroup_create_args {
+ __u64 create;
+ __u64 qgroupid;
+ };
+
+ Before calling this ioctl, the 'create' field should be filled
+ with the aproppriate value depending on if the user wants to
+ create or remove a quota group (0 for removing, everything else
+ for creating). Also, the 'qgroupid' field should be filled with
+ the value for the quota group id that is to be created.
+
+BTRFS_IOC_QGROUP_ASSIGN - Asigning or removing a quota group as child group
+
+ Asign or remove a quota group as child quota group of another
+ group in the btrfs filesystem. The asignment is done using the
+ ioctl's third argument which represents a pointert to a following type:
+
+ struct btrfs_ioctl_qgroup_assign_args {
+ __u64 assign;
+ __u64 src;
+ __u64 dst;
+ };
+
+ Before calling this ioctl, the 'assign' field should be filled with
+ the aproppriate value depending on if the user wants to asign or remove
+ a quota group as a child quota group of another group (0 for removing,
+ everythin else for asigning). Also, the 'src' and 'dst' fields should
+ be filled with the aproppriate quota group id values depending on which
+ quota group needs to asigned or removed as child quota group of another
+ group ('src' gets asigned or removed as child group of 'dst').
+
+BTRFS_IOC_QGROUP_LIMIT - Limiting the size of a quota group
+
+ Limit the size of a quota group. The size of the quota group is limited
+ with the ioctls third argument which represents a pointer to a following
+ type:
+
+ struct btrfs_ioctl_qgroup_limit_args {
+ __u64 qgroupid;
+ struct btrfs_qgroup_limit lim;
+ };
+
+ Before calling this ioctl, the 'qgroup' id field should be filled with
+ aproppriate value of the quota group id for which the size is to be
+ limited. The second field is of following type:
+
+ struct btrfs_qgroup_limit {
+ __u64 flags;
+ __u64 max_rfer;
+ __u64 max_excl;
+ __u64 rsv_rfer;
+ __u64 rsv_excl;
+ };
+
+ The 'max_rfer' field should be filled with the size to which the quota
+ group should be limited. The 'flags' field can be used for passing
+ additional options and can have values which can be found on:
+ https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/btrfs.h...
+
+BTRFS_IOC_QUOTA_RESCAN_STATUS - Checking status of running rescan operation
+
+ Check status of a running rescan operation. The status is checked using
+ the ioctl's third argument which represents a pointer to a following type:
+
+ struct btrfs_ioctl_quota_rescan_args {
+ __u64 flags;
+ __u64 progress;
+ __u64 reserved[6];
+ };
+
+ If there is a rescan operation running, 'flags' field is set to 1, and
+ 'progress' field is set to aproppriate value which represents the progress
+ of the operation.
+
+BTRFS_IOC_QUOTA_RESCAN - Starting a rescan operation
+
+ Start ar rescan operation to Trash all quota groups and scan the metadata
+ again with the current config. Before calling this ioctl,
+ BTRFS_IOC_QUOTA_RESCAN_STATUS sould be run to check if there is already a
+ rescan operation runing. After that ioctl call, the received
+ 'struct btrfs_ioctl_quota_rescan_args' should be than passed as this ioctls
+ third argument.
+
+BTRFS_IOC_QUOTA_RESCAN_WAIT - Waiting for a rescan operation to finish
+
+ Wait until a rescan operation is finished (if there is a rescan operation
+ running). The third ioctls argument is ignored.
+
+Implementation notes:
+
+ Almost all of the ioctls in this patch use structure types as third arguments.
+ That is the reason why aproppriate thunk definitions were added in file
+ 'syscall_types.h'.
+
+Signed-off-by: Filip Bozuta <Filip.Bozuta(a)syrmia.com>
+Tested-by: Daniel P. Berrangé <berrange(a)redhat.com>
+Message-Id: <20200823195014.116226-8-Filip.Bozuta(a)syrmia.com>
+Signed-off-by: Laurent Vivier <laurent(a)vivier.eu>
+---
+ linux-user/ioctls.h | 27 +++++++++++++++++++++++++++
+ linux-user/syscall_defs.h | 7 +++++++
+ linux-user/syscall_types.h | 29 +++++++++++++++++++++++++++++
+ 3 files changed, 63 insertions(+)
+
+diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h
+index 728880b9f3..882bfb3e88 100644
+--- a/linux-user/ioctls.h
++++ b/linux-user/ioctls.h
+@@ -227,6 +227,33 @@
+ IOCTL(BTRFS_IOC_LOGICAL_INO, IOC_RW,
+ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_logical_ino_args)))
+ #endif
++#ifdef BTRFS_IOC_QUOTA_CTL
++ IOCTL(BTRFS_IOC_QUOTA_CTL, IOC_RW,
++ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_quota_ctl_args)))
++#endif
++#ifdef BTRFS_IOC_QGROUP_ASSIGN
++ IOCTL(BTRFS_IOC_QGROUP_ASSIGN, IOC_W,
++ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_qgroup_assign_args)))
++#endif
++#ifdef BTRFS_IOC_QGROUP_CREATE
++ IOCTL(BTRFS_IOC_QGROUP_CREATE, IOC_W,
++ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_qgroup_create_args)))
++#endif
++#ifdef BTRFS_IOC_QGROUP_LIMIT
++ IOCTL(BTRFS_IOC_QGROUP_LIMIT, IOC_R,
++ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_qgroup_limit_args)))
++#endif
++#ifdef BTRFS_IOC_QUOTA_RESCAN
++ IOCTL(BTRFS_IOC_QUOTA_RESCAN, IOC_W,
++ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_quota_rescan_args)))
++#endif
++#ifdef BTRFS_IOC_QUOTA_RESCAN_STATUS
++ IOCTL(BTRFS_IOC_QUOTA_RESCAN_STATUS, IOC_R,
++ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_quota_rescan_args)))
++#endif
++#ifdef BTRFS_IOC_QUOTA_RESCAN_WAIT
++ IOCTL(BTRFS_IOC_QUOTA_RESCAN_WAIT, 0, TYPE_NULL)
++#endif
+ #ifdef BTRFS_IOC_GET_DEV_STATS
+ IOCTL(BTRFS_IOC_GET_DEV_STATS, IOC_RW,
+ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_get_dev_stats)))
+diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
+index 1d0bfb5479..10a7f91016 100644
+--- a/linux-user/syscall_defs.h
++++ b/linux-user/syscall_defs.h
+@@ -985,6 +985,13 @@ struct target_rtc_pll_info {
+ #define TARGET_BTRFS_IOC_DEV_INFO TARGET_IOWRU(BTRFS_IOCTL_MAGIC, 30)
+ #define TARGET_BTRFS_IOC_INO_PATHS TARGET_IOWRU(BTRFS_IOCTL_MAGIC, 35)
+ #define TARGET_BTRFS_IOC_LOGICAL_INO TARGET_IOWRU(BTRFS_IOCTL_MAGIC, 36)
++#define TARGET_BTRFS_IOC_QUOTA_CTL TARGET_IOWRU(BTRFS_IOCTL_MAGIC, 40)
++#define TARGET_BTRFS_IOC_QGROUP_ASSIGN TARGET_IOWU(BTRFS_IOCTL_MAGIC, 41)
++#define TARGET_BTRFS_IOC_QGROUP_CREATE TARGET_IOWU(BTRFS_IOCTL_MAGIC, 42)
++#define TARGET_BTRFS_IOC_QGROUP_LIMIT TARGET_IORU(BTRFS_IOCTL_MAGIC, 43)
++#define TARGET_BTRFS_IOC_QUOTA_RESCAN TARGET_IOWU(BTRFS_IOCTL_MAGIC, 44)
++#define TARGET_BTRFS_IOC_QUOTA_RESCAN_STATUS TARGET_IORU(BTRFS_IOCTL_MAGIC, 45)
++#define TARGET_BTRFS_IOC_QUOTA_RESCAN_WAIT TARGET_IO(BTRFS_IOCTL_MAGIC, 46)
+ #define TARGET_BTRFS_IOC_GET_DEV_STATS TARGET_IOWRU(BTRFS_IOCTL_MAGIC, 52)
+ #define TARGET_BTRFS_IOC_GET_FEATURES TARGET_IORU(BTRFS_IOCTL_MAGIC, 57)
+ #define TARGET_BTRFS_IOC_SET_FEATURES TARGET_IOWU(BTRFS_IOCTL_MAGIC, 57)
+diff --git a/linux-user/syscall_types.h b/linux-user/syscall_types.h
+index 5566d101c2..d9b7106a69 100644
+--- a/linux-user/syscall_types.h
++++ b/linux-user/syscall_types.h
+@@ -454,6 +454,35 @@ STRUCT(btrfs_ioctl_get_dev_stats,
+ 128 - 2 - BTRFS_DEV_STAT_VALUES_MAX)) /* unused */
+ #endif
+
++STRUCT(btrfs_ioctl_quota_ctl_args,
++ TYPE_ULONGLONG, /* cmd */
++ TYPE_ULONGLONG) /* status */
++
++STRUCT(btrfs_ioctl_quota_rescan_args,
++ TYPE_ULONGLONG, /* flags */
++ TYPE_ULONGLONG, /* progress */
++ MK_ARRAY(TYPE_ULONGLONG, 6)) /* reserved */
++
++STRUCT(btrfs_ioctl_qgroup_assign_args,
++ TYPE_ULONGLONG, /* assign */
++ TYPE_ULONGLONG, /* src */
++ TYPE_ULONGLONG) /* dst */
++
++STRUCT(btrfs_ioctl_qgroup_create_args,
++ TYPE_ULONGLONG, /* create */
++ TYPE_ULONGLONG) /* qgroupid */
++
++STRUCT(btrfs_qgroup_limit,
++ TYPE_ULONGLONG, /* flags */
++ TYPE_ULONGLONG, /* max_rfer */
++ TYPE_ULONGLONG, /* max_excl */
++ TYPE_ULONGLONG, /* rsv_rfer */
++ TYPE_ULONGLONG) /* rsv_excl */
++
++STRUCT(btrfs_ioctl_qgroup_limit_args,
++ TYPE_ULONGLONG, /* qgroupid */
++ MK_STRUCT(STRUCT_btrfs_qgroup_limit)) /* lim */
++
+ STRUCT(btrfs_ioctl_feature_flags,
+ TYPE_ULONGLONG, /* compat_flags */
+ TYPE_ULONGLONG, /* compat_ro_flags */
+--
+2.26.2
+
diff --git a/0009-linux-user-Add-support-for-btrfs-ioctls-used-to-scru.patch b/0009-linux-user-Add-support-for-btrfs-ioctls-used-to-scru.patch
new file mode 100644
index 0000000..c64a48e
--- /dev/null
+++ b/0009-linux-user-Add-support-for-btrfs-ioctls-used-to-scru.patch
@@ -0,0 +1,142 @@
+From 5695918e7c599f21fd6913a61160c482a0e41639 Mon Sep 17 00:00:00 2001
+From: Filip Bozuta <Filip.Bozuta(a)syrmia.com>
+Date: Thu, 3 Sep 2020 01:27:01 +0200
+Subject: [PATCH 9/9] linux-user: Add support for btrfs ioctls used to scrub a
+ filesystem
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This patch implements functionality for following ioctls:
+
+BTRFS_IOC_SCRUB - Starting a btrfs filesystem scrub
+
+ Start a btrfs filesystem scrub. The third ioctls argument
+ is a pointer to a following type:
+
+ struct btrfs_ioctl_scrub_args {
+ __u64 devid; /* in */
+ __u64 start; /* in */
+ __u64 end; /* in */
+ __u64 flags; /* in */
+ struct btrfs_scrub_progress progress; /* out */
+ /* pad to 1k */
+ __u64 unused[(1024-32-sizeof(struct btrfs_scrub_progress))/8];
+ };
+
+ Before calling this ioctl, field 'devid' should be filled
+ with value that represents the device id of the btrfs filesystem
+ for which the scrub is to be started.
+
+BTRFS_IOC_SCRUB_CANCEL - Canceling scrub of a btrfs filesystem
+
+ Cancel a btrfs filesystem scrub if it is running. The third
+ ioctls argument is ignored.
+
+BTRFS_IOC_SCRUB_PROGRESS - Getting status of a running scrub
+
+ Read the status of a running btrfs filesystem scrub. The third
+ ioctls argument is a pointer to the above mentioned
+ 'struct btrfs_ioctl_scrub_args'. Similarly as with 'BTRFS_IOC_SCRUB',
+ the 'devid' field should be filled with value that represents the
+ id of the btrfs device for which the scrub has started. The status
+ of a running scrub is returned in the field 'progress' which is
+ of type 'struct btrfs_scrub_progress' and its definition can be
+ found at:
+ https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/btrfs.h...
+
+Implementation nots:
+
+ Ioctls in this patch use type 'struct btrfs_ioctl_scrub_args' as their
+ third argument. That is the reason why an aproppriate thunk type
+ definition is added in file 'syscall_types.h'.
+
+Signed-off-by: Filip Bozuta <Filip.Bozuta(a)syrmia.com>
+Tested-by: Daniel P. Berrangé <berrange(a)redhat.com>
+Message-Id: <20200823195014.116226-9-Filip.Bozuta(a)syrmia.com>
+Signed-off-by: Laurent Vivier <laurent(a)vivier.eu>
+---
+ linux-user/ioctls.h | 11 +++++++++++
+ linux-user/syscall_defs.h | 3 +++
+ linux-user/syscall_types.h | 29 +++++++++++++++++++++++++++++
+ 3 files changed, 43 insertions(+)
+
+diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h
+index 882bfb3e88..e3bfe78774 100644
+--- a/linux-user/ioctls.h
++++ b/linux-user/ioctls.h
+@@ -215,6 +215,17 @@
+ #ifdef BTRFS_IOC_SUBVOL_SETFLAGS
+ IOCTL(BTRFS_IOC_SUBVOL_SETFLAGS, IOC_W, MK_PTR(TYPE_ULONGLONG))
+ #endif
++#ifdef BTRFS_IOC_SCRUB
++ IOCTL(BTRFS_IOC_SCRUB, IOC_RW,
++ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_scrub_args)))
++#endif
++#ifdef BTRFS_IOC_SCRUB_CANCEL
++ IOCTL(BTRFS_IOC_SCRUB_CANCEL, 0, TYPE_NULL)
++#endif
++#ifdef BTRFS_IOC_SCRUB_PROGRESS
++ IOCTL(BTRFS_IOC_SCRUB_PROGRESS, IOC_RW,
++ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_scrub_args)))
++#endif
+ #ifdef BTRFS_IOC_DEV_INFO
+ IOCTL(BTRFS_IOC_DEV_INFO, IOC_RW,
+ MK_PTR(MK_STRUCT(STRUCT_btrfs_ioctl_dev_info_args)))
+diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
+index 10a7f91016..969377d622 100644
+--- a/linux-user/syscall_defs.h
++++ b/linux-user/syscall_defs.h
+@@ -982,6 +982,9 @@ struct target_rtc_pll_info {
+ abi_ullong)
+ #define TARGET_BTRFS_IOC_SUBVOL_SETFLAGS TARGET_IOW(BTRFS_IOCTL_MAGIC, 26,\
+ abi_ullong)
++#define TARGET_BTRFS_IOC_SCRUB TARGET_IOWRU(BTRFS_IOCTL_MAGIC, 27)
++#define TARGET_BTRFS_IOC_SCRUB_CANCEL TARGET_IO(BTRFS_IOCTL_MAGIC, 28)
++#define TARGET_BTRFS_IOC_SCRUB_PROGRESS TARGET_IOWRU(BTRFS_IOCTL_MAGIC, 29)
+ #define TARGET_BTRFS_IOC_DEV_INFO TARGET_IOWRU(BTRFS_IOCTL_MAGIC, 30)
+ #define TARGET_BTRFS_IOC_INO_PATHS TARGET_IOWRU(BTRFS_IOCTL_MAGIC, 35)
+ #define TARGET_BTRFS_IOC_LOGICAL_INO TARGET_IOWRU(BTRFS_IOCTL_MAGIC, 36)
+diff --git a/linux-user/syscall_types.h b/linux-user/syscall_types.h
+index d9b7106a69..789723cfb9 100644
+--- a/linux-user/syscall_types.h
++++ b/linux-user/syscall_types.h
+@@ -421,6 +421,35 @@ STRUCT(btrfs_ioctl_ino_lookup_user_args,
+ MK_ARRAY(TYPE_CHAR, BTRFS_INO_LOOKUP_USER_PATH_MAX)) /* path */
+ #endif
+
++#if defined(BTRFS_IOC_SCRUB) || defined(BTRFS_IOC_SCRUB_PROGRESS)
++STRUCT(btrfs_scrub_progress,
++ TYPE_ULONGLONG, /* data_extents_scrubbed */
++ TYPE_ULONGLONG, /* tree_extents_scrubbed */
++ TYPE_ULONGLONG, /* data_bytes_scrubbed */
++ TYPE_ULONGLONG, /* tree_bytes_scrubbed */
++ TYPE_ULONGLONG, /* read_errors */
++ TYPE_ULONGLONG, /* csum_errors */
++ TYPE_ULONGLONG, /* verify_errors */
++ TYPE_ULONGLONG, /* no_csum */
++ TYPE_ULONGLONG, /* csum_discards */
++ TYPE_ULONGLONG, /* super_errors */
++ TYPE_ULONGLONG, /* malloc_errors */
++ TYPE_ULONGLONG, /* uncorrectable_errors */
++ TYPE_ULONGLONG, /* corrected_er */
++ TYPE_ULONGLONG, /* last_physical */
++ TYPE_ULONGLONG) /* unverified_errors */
++
++STRUCT(btrfs_ioctl_scrub_args,
++ TYPE_ULONGLONG, /* devid */
++ TYPE_ULONGLONG, /* start */
++ TYPE_ULONGLONG, /* end */
++ TYPE_ULONGLONG, /* flags */
++ MK_STRUCT(STRUCT_btrfs_scrub_progress), /* progress */
++ MK_ARRAY(TYPE_ULONGLONG,
++ (1024 - 32 -
++ sizeof(struct btrfs_scrub_progress)) / 8)) /* unused */
++#endif
++
+ #ifdef BTRFS_IOC_DEV_INFO
+ STRUCT(btrfs_ioctl_dev_info_args,
+ TYPE_ULONGLONG, /* devid */
+--
+2.26.2
+
diff --git a/qemu.spec b/qemu.spec
index 00d85fb..6d5b368 100644
--- a/qemu.spec
+++ b/qemu.spec
@@ -170,13 +170,23 @@
Summary: QEMU is a FAST! processor emulator
Name: qemu
Version: 5.1.0
-Release: 3%{?rcrel}%{?dist}
+Release: 4%{?rcrel}%{?dist}
Epoch: 2
License: GPLv2 and BSD and MIT and CC-BY
URL: http://www.qemu.org/
Source0: http://wiki.qemu-project.org/download/%{name}-%{version}%{?rcstr}.tar.xz
+Patch1: 0001-linux-user-fix-implicit-conversion-from-enumeration-.patch
+Patch2: 0002-linux-user-Add-support-for-a-group-of-btrfs-ioctls-u.patch
+Patch3: 0003-linux-user-Add-support-for-a-group-of-btrfs-ioctls-u.patch
+Patch4: 0004-linux-user-Add-support-for-btrfs-ioctls-used-to-mani.patch
+Patch5: 0005-linux-user-Add-support-for-btrfs-ioctls-used-to-get-.patch
+Patch6: 0006-linux-user-Add-support-for-a-group-of-btrfs-inode-io.patch
+Patch7: 0007-linux-user-Add-support-for-two-btrfs-ioctls-used-for.patch
+Patch8: 0008-linux-user-Add-support-for-btrfs-ioctls-used-to-mana.patch
+Patch9: 0009-linux-user-Add-support-for-btrfs-ioctls-used-to-scru.patch
+
# guest agent service
Source10: qemu-guest-agent.service
Source17: qemu-ga.sysconfig
@@ -1898,6 +1908,9 @@ getent passwd qemu >/dev/null || \
%changelog
+* Thu Sep 3 2020 Daniel P. Berrangé <berrange(a)redhat.com> - 5.1.0-4
+- Add btrfs ioctls to linux-user (rhbz #1872918)
+
* Tue Aug 18 2020 Tom Stellard <tstellar(a)redhat.com> - 5.1.0-3
- Add BuildRequires: gcc
- https://fedoraproject.org/wiki/Packaging:C_and_C%2B%2B#BuildRequires_and_...
commit 3927dda1185b1d7a82e9427936cf5bd828934ef9
Author: Cole Robinson <crobinso(a)redhat.com>
Date: Mon Aug 31 15:01:17 2020 -0400
spec: Fix test conditionals
And update the comment explaining why things are still disabled
Signed-off-by: Cole Robinson <crobinso(a)redhat.com>
diff --git a/qemu.spec b/qemu.spec
index fa48903..00d85fb 100644
--- a/qemu.spec
+++ b/qemu.spec
@@ -1396,11 +1396,13 @@ chmod +x %{buildroot}%{_libdir}/qemu/*.so
%global tests_skip 1
%endif
-# 2020-08-17: tests still failing locally but output is working
+# 2020-08-31: tests passing, but s390x fails due to
+# spurious warning breaking an iotest case
+# https://lists.gnu.org/archive/html/qemu-devel/2020-08/msg03279.html
%global tests_nofail 1
pushd build-dynamic
-%if %{tests_skip}
+%if !%{tests_skip}
%if %{tests_nofail}
make check V=1 || :
%else
commit 3fa99d6aac869fad28b7a1ec8b4ea1ad417c98fa
Author: Tom Stellard <tstellar(a)redhat.com>
Date: Tue Aug 18 14:21:26 2020 +0000
Add BuildRequires: gcc
https://fedoraproject.org/wiki/Packaging:C_and_C%2B%2B#BuildRequires_and_...
diff --git a/qemu.spec b/qemu.spec
index 7dc7376..fa48903 100644
--- a/qemu.spec
+++ b/qemu.spec
@@ -170,7 +170,7 @@
Summary: QEMU is a FAST! processor emulator
Name: qemu
Version: 5.1.0
-Release: 2%{?rcrel}%{?dist}
+Release: 3%{?rcrel}%{?dist}
Epoch: 2
License: GPLv2 and BSD and MIT and CC-BY
URL: http://www.qemu.org/
@@ -195,6 +195,7 @@ Source20: kvm-x86.modprobe.conf
Source21: 95-kvm-ppc64-memlock.conf
+BuildRequires: gcc
# documentation deps
BuildRequires: texinfo
# For /usr/bin/pod2man
@@ -1895,6 +1896,10 @@ getent passwd qemu >/dev/null || \
%changelog
+* Tue Aug 18 2020 Tom Stellard <tstellar(a)redhat.com> - 5.1.0-3
+- Add BuildRequires: gcc
+- https://fedoraproject.org/wiki/Packaging:C_and_C%2B%2B#BuildRequires_and_...
+
* Mon Aug 17 2020 Cole Robinson <aintdiscole(a)gmail.com> - 5.1.0-2
- Disable dtrace generation to fix use of modules (bz 1869339)
3 years, 8 months