From d4e92d617c9f50f4e6d00313065accd6813a9cbb Mon Sep 17 00:00:00 2001 From: Alejandro Curci Date: Tue, 12 Nov 2024 13:38:13 -0300 Subject: [PATCH 1/4] W-16889209: Changes to be FIPS compatible --- .gitignore | 4 + pom.xml | 28 ++++- src/test/docker/tls/activemq.xml | 3 +- .../jms/test/ActiveMQSSLServer.java | 8 +- .../jms/test/ssl/ActiveMQSSLServer.java | 10 +- ...nericConnectionProviderSecureTestCase.java | 12 +- .../munit/activemq-over-ssl-test-case.xml | 25 +++- ...mq-ssl-listener-reconnection-test-case.xml | 2 +- .../munit/xa/activemq-ssl-xa-test-case.xml | 2 +- src/test/resources/activemq-fips.xml | 118 ++++++++++++++++++ .../config/activemq/activemq-default-ssl.xml | 24 ---- src/test/resources/tls/broker.ks.bcfks | Bin 0 -> 2751 bytes src/test/resources/tls/broker.ts.bcfks | Bin 0 -> 1359 bytes .../resources/tls/client-truststore-new.bcfks | Bin 0 -> 1718 bytes .../resources/tls/client-truststore.bcfks | Bin 0 -> 1718 bytes src/test/resources/tls/client-truststore.jks | Bin 0 -> 1313 bytes src/test/resources/tls/client.ks.bcfks | Bin 0 -> 2750 bytes src/test/resources/tls/client.ks.jks | Bin 0 -> 2242 bytes src/test/resources/tls/client.ts.bcfks | Bin 0 -> 1359 bytes src/test/resources/tls/client.ts.jks | Bin 0 -> 954 bytes .../tls/genericConnectionTests.bcfks | Bin 0 -> 3525 bytes 21 files changed, 203 insertions(+), 33 deletions(-) create mode 100644 src/test/resources/activemq-fips.xml delete mode 100644 src/test/resources/config/activemq/activemq-default-ssl.xml create mode 100644 src/test/resources/tls/broker.ks.bcfks create mode 100644 src/test/resources/tls/broker.ts.bcfks create mode 100644 src/test/resources/tls/client-truststore-new.bcfks create mode 100644 src/test/resources/tls/client-truststore.bcfks create mode 100644 src/test/resources/tls/client-truststore.jks create mode 100644 src/test/resources/tls/client.ks.bcfks create mode 100644 src/test/resources/tls/client.ks.jks create mode 100644 src/test/resources/tls/client.ts.bcfks create mode 100644 src/test/resources/tls/client.ts.jks create mode 100644 src/test/resources/tls/genericConnectionTests.bcfks diff --git a/.gitignore b/.gitignore index a68d8a6b..d5655132 100644 --- a/.gitignore +++ b/.gitignore @@ -29,3 +29,7 @@ testdir/ hostkey.ser *.h2.db *.factorypath +apache-activemq-5.15.9-bin.tar.gz +FipsUtils.java +FipsTestCase.xml +tls-fips140-2.conf diff --git a/pom.xml b/pom.xml index e94eb8ae..2faed3f9 100644 --- a/pom.xml +++ b/pom.xml @@ -57,6 +57,11 @@ 4.2 LICENSE_HEADER_CPAL.txt 2023 + + PKCS12 + p12 + JKS + jks @@ -421,7 +426,9 @@ docker - true + + os.name + @@ -524,6 +531,25 @@ + + + fips140-2 + + + mule.security.model + fips140-2 + + + + BCFKS + bcfks + BCFKS + bcfks + + + + + diff --git a/src/test/docker/tls/activemq.xml b/src/test/docker/tls/activemq.xml index c91d22cc..5eb3bdfa 100644 --- a/src/test/docker/tls/activemq.xml +++ b/src/test/docker/tls/activemq.xml @@ -123,7 +123,8 @@ - + diff --git a/src/test/java/org/mule/extensions/jms/test/ActiveMQSSLServer.java b/src/test/java/org/mule/extensions/jms/test/ActiveMQSSLServer.java index 0a0800ca..58d8f2f4 100644 --- a/src/test/java/org/mule/extensions/jms/test/ActiveMQSSLServer.java +++ b/src/test/java/org/mule/extensions/jms/test/ActiveMQSSLServer.java @@ -16,6 +16,8 @@ */ public class ActiveMQSSLServer { + public static final String FIPS140_2 = "fips140-2"; + public static final String MULE_SECURITY_MODEL_PROPERTY = "mule.security.model"; private static final String ACTIVEMQ_PORT = "activemq.port"; private static BrokerService brokerService; private static boolean started = false; @@ -24,7 +26,11 @@ public static void start(String port) throws Exception { if (!started) { System.setProperty(ACTIVEMQ_PORT, port); try { - brokerService = BrokerFactory.createBroker(new URI("xbean:activemq.xml")); + if (FIPS140_2.equals(System.getProperty(MULE_SECURITY_MODEL_PROPERTY))) { + brokerService = BrokerFactory.createBroker(new URI("xbean:activemq-fips.xml")); + } else { + brokerService = BrokerFactory.createBroker(new URI("xbean:activemq.xml")); + } brokerService.start(); } finally { System.clearProperty(ACTIVEMQ_PORT); diff --git a/src/test/java/org/mule/extensions/jms/test/ssl/ActiveMQSSLServer.java b/src/test/java/org/mule/extensions/jms/test/ssl/ActiveMQSSLServer.java index 37ed71a7..a9b67e42 100644 --- a/src/test/java/org/mule/extensions/jms/test/ssl/ActiveMQSSLServer.java +++ b/src/test/java/org/mule/extensions/jms/test/ssl/ActiveMQSSLServer.java @@ -16,6 +16,9 @@ */ public class ActiveMQSSLServer { + public static final String FIPS140_2 = "fips140-2"; + public static final String MULE_SECURITY_MODEL_PROPERTY = "mule.security.model"; + private static final String ACTIVEMQ_PORT = "activemq.port"; private static BrokerService brokerService; private static boolean started = false; @@ -24,7 +27,12 @@ public static void start(String port) throws Exception { if (!started) { System.setProperty(ACTIVEMQ_PORT, port); try { - brokerService = BrokerFactory.createBroker(new URI("xbean:activemq.xml")); + if (FIPS140_2.equals(System.getProperty(MULE_SECURITY_MODEL_PROPERTY))) { + brokerService = BrokerFactory.createBroker(new URI("xbean:activemq-fips.xml")); + } else { + brokerService = BrokerFactory.createBroker(new URI("xbean:activemq.xml")); + } + brokerService.start(); } finally { System.clearProperty(ACTIVEMQ_PORT); diff --git a/src/test/java/org/mule/extensions/jms/test/ssl/GenericConnectionProviderSecureTestCase.java b/src/test/java/org/mule/extensions/jms/test/ssl/GenericConnectionProviderSecureTestCase.java index d381f0a7..f4c096ed 100644 --- a/src/test/java/org/mule/extensions/jms/test/ssl/GenericConnectionProviderSecureTestCase.java +++ b/src/test/java/org/mule/extensions/jms/test/ssl/GenericConnectionProviderSecureTestCase.java @@ -33,6 +33,9 @@ @PrepareForTest({SSLContext.class, FileInputStream.class, GenericConnectionProvider.class, TrustManagerFactory.class}) public class GenericConnectionProviderSecureTestCase { + public static final String FIPS140_2 = "fips140-2"; + public static final String MULE_SECURITY_MODEL_PROPERTY = "mule.security.model"; + @Before public void setUp() { PowerMockito.mockStatic(SSLContext.class); @@ -42,7 +45,12 @@ public void setUp() { @Test public void testGetConnectionFactory_withProperties() throws Exception { System.setProperty("mule.jms.generic.additionalCertificatePassword", "changeit"); - System.setProperty("mule.jms.generic.additionalCertificateFileName", "tls/genericConnectionTests.jks"); + String ksExt = "jks"; + if (FIPS140_2.equals(System.getProperty(MULE_SECURITY_MODEL_PROPERTY))) { + ksExt = "bcfks"; + } + + System.setProperty("mule.jms.generic.additionalCertificateFileName", "tls/genericConnectionTests." + ksExt); SSLContext mockSSLContext = PowerMockito.mock(SSLContext.class); SSLParameters mockSSLParameters = PowerMockito.mock(SSLParameters.class); @@ -61,7 +69,7 @@ public void testGetConnectionFactory_withProperties() throws Exception { GenericConnectionProvider connectionProvider = PowerMockito.spy(new GenericConnectionProvider()); PowerMockito.doReturn(mockKeyStore).when(connectionProvider, "getKeyStoreWithCustomCerts", any(Optional.class), anyString()); - PowerMockito.when(connectionProvider, "getTruststoreFile", "tls/genericConnectionTests.jks") + PowerMockito.when(connectionProvider, "getTruststoreFile", "tls/genericConnectionTests." + ksExt) .thenReturn(Optional.of(mockTruststoreFile)); FileInputStream mockFileInputStream = PowerMockito.mock(FileInputStream.class); diff --git a/src/test/munit/activemq-over-ssl-test-case.xml b/src/test/munit/activemq-over-ssl-test-case.xml index 0e5d391b..db1b0969 100644 --- a/src/test/munit/activemq-over-ssl-test-case.xml +++ b/src/test/munit/activemq-over-ssl-test-case.xml @@ -3,12 +3,14 @@ xmlns:jms="http://www.mulesoft.org/schema/mule/jms" xmlns:java="http://www.mulesoft.org/schema/mule/java" xmlns:munit-tools="http://www.mulesoft.org/schema/mule/munit-tools" + xmlns:mtf="http://www.mulesoft.org/schema/mule/mtf" xmlns="http://www.mulesoft.org/schema/mule/core" xmlns:tls="http://www.mulesoft.org/schema/mule/tls" xmlns:munit="http://www.mulesoft.org/schema/mule/munit" xsi:schemaLocation="http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd http://www.mulesoft.org/schema/mule/jms http://www.mulesoft.org/schema/mule/jms/current/mule-jms.xsd http://www.mulesoft.org/schema/mule/tls http://www.mulesoft.org/schema/mule/tls/current/mule-tls.xsd + http://www.mulesoft.org/schema/mule/mtf http://www.mulesoft.org/schema/mule/mtf/current/mule-mtf.xsd http://www.mulesoft.org/schema/mule/munit-tools http://www.mulesoft.org/schema/mule/munit-tools/current/mule-munit-tools.xsd http://www.mulesoft.org/schema/mule/java http://www.mulesoft.org/schema/mule/java/current/mule-java.xsd http://www.mulesoft.org/schema/mule/munit http://www.mulesoft.org/schema/mule/munit/current/mule-munit.xsd"> @@ -38,11 +40,16 @@ + + + + + - + @@ -79,4 +86,20 @@ + + + + + + + + + + + + + + diff --git a/src/test/munit/reconnection/activemq-ssl-listener-reconnection-test-case.xml b/src/test/munit/reconnection/activemq-ssl-listener-reconnection-test-case.xml index 9c46d61c..d52bed52 100644 --- a/src/test/munit/reconnection/activemq-ssl-listener-reconnection-test-case.xml +++ b/src/test/munit/reconnection/activemq-ssl-listener-reconnection-test-case.xml @@ -22,7 +22,7 @@ - + diff --git a/src/test/munit/xa/activemq-ssl-xa-test-case.xml b/src/test/munit/xa/activemq-ssl-xa-test-case.xml index 5c541d32..0f27bdb9 100644 --- a/src/test/munit/xa/activemq-ssl-xa-test-case.xml +++ b/src/test/munit/xa/activemq-ssl-xa-test-case.xml @@ -21,7 +21,7 @@ - + diff --git a/src/test/resources/activemq-fips.xml b/src/test/resources/activemq-fips.xml new file mode 100644 index 00000000..e9b9eae9 --- /dev/null +++ b/src/test/resources/activemq-fips.xml @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/config/activemq/activemq-default-ssl.xml b/src/test/resources/config/activemq/activemq-default-ssl.xml deleted file mode 100644 index 8afc1cff..00000000 --- a/src/test/resources/config/activemq/activemq-default-ssl.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/src/test/resources/tls/broker.ks.bcfks b/src/test/resources/tls/broker.ks.bcfks new file mode 100644 index 0000000000000000000000000000000000000000..909bb887bebb84c930313b023382149e67d1ddb9 GIT binary patch literal 2751 zcmV;w3PANRf(pAZf(iaGfs_UbDuzgg_YDCB4KRU*Fk}V^Duzgg_YDCB3@}#&K&=_t zmflCas#dtU_&WG-!jt{PID`}EcSENAOyxzc9&0#gDT~2USM)7k6HNC9O71OYEF5d;hwTNI}D zkZSSG`B5(d0SE+w31iJ#ouzi+h|p~hjx~l}*z^fG<8Wmt(SkOI#$GA)H%PB)Y7Tm4 zRCIcqHcB=>90wa7W;rT^wyfqI`OZ4R>`bnx&MUo4uu~N1yyE>#ZI_70LD|?*zi%(I z$za#DfE#WObc*ia+znQ0SrA)*xN_~-N_NEQhN>WAO^NWE==YW0m4S9nt$Yeg6k-4& z@m{}QL2Db7#nEgsaGnTDjU99_&Tdb)&UT?NfEU4vnEj=Y0NA<_TbyV-frUwztl9W2 zzAkgYJk@8UCDELW@eIOP-fow3kpA9PDE?+%`z+1~XkKlro@kFV?V5Ctqw;FcJCZj3 zt0BkzBH;*VgTFY#dg=t>{_@MhoRyjwsu3*;Wi9xDT&LMgB&h8?cV z`w9Y!UWd3L>y!pA_XTNXwvlizWL4Orxz>;=w@14Hl+dZ%sEY1t2Uh@pEY+^X#rCx( z4a}thwEfQNRt8m@`xdyP5+K`#`-NQ^qE_wyW=){dZWkz}j6)T%qnA7$VzzAb-V1U+ zLS#O1TDK74Zo_)}Pdhc%O&`qLCV2-?%}x()Y2zz|zl_$tyfRB}hQCq)c!A%7v6|r} zVJ`C%#e$$%;&DdWI`Rv~&9Wu7m@u?o*_KzxUC0k4xq7YcxDW5EL=G~sU5|T0w=6wd z!#4PS@igm4cNe}3!4w2ca3J0 zzCMJnYr@)sY5)&ZPAjuBYBUZZB<4Jo^kPxv`M;gP-1p(5`;20YemLhl3z+#s##onX zEQeru!}U=b-5%r#0Zcp4gm>r${?%M3x_L)L00ssKv72W$h=5njvAkO zI&Q`QV;JsrV|zALov{R?IHKaLo555~cTuJtZc!%O|0$T@-Q#%I;RmH=7@X#gzC^3yO)B>$<7M=W3j>_|h~em?U~AOTQ%`?@x~k|XNf{o1 zRCo|6r_Y~2Z_x7oJrZV3exXHVcxaM5U09IC;5+~S=#w+%|1PYTYAHdJu_Mp3r|N$n z6#GY?N)f<(V{7wjJ_@UfsN$D{Q&vTuBwu?Uwj zI+%HXPtP5fc$IdAGPc|G75{IS;Xx0EW(${Mzh=cBHC@hJzXSv3wh$qv#!{YOWjJrH zbb-F)Dj5hURl(dKsr4wY2E0v}&5{^&f3fw+bcO4~HiNSzAc7w<{96~#*L|JhHMlW|E-mzaD`evyAIl(lMb) z;WF@{$~D&EJ7nq{{& zMRa&H>bV7bAAPIlF4#S=gu5@?>s83jy0M{J!1MSRIF9a{*;;$OVLIxAa*eorUoesU zgT9>fB~joBRXwVRW;RuC_RS5~>zD_SM8DF>q}D{*&Usdg3DlDvJ06PFA6aCt0KCBU znetaBK|8 z20U>H=6T8$k_f=W|Az3e!heq2dWH+Yh58X5|1ofTB)&HGsPP>Wokw=xt0pw6@wrFs z(j{~EINhYK-=&vXoFP3mpR0qhUluZ(N=#dwHF+kx3VfB#pR|V^KqcDNCFboC=Duzgg_YDFI1pqK)1_>&LNQU&R|G)!yxMZ$V5GI($J78eYA%AhyBDn5V*N&CIqSIro7CWzBL zc}RA{F@9Ctzp;ZD)bGA9YUQH>0zd!)0YESe1_&yKNQUNC9O71OYEF5d;jZ4vN6} zlga!dSVzAC0SE+w1M}Cz-SXC1O@g=!&h=m}p%lWb-@CW9^+G3r3RMT0mssCSv4j{W z0GII1^p7(JuQEIyFh(`MQAWJ}_5?n9L}W;vX9m?nUYQ?p&d73QmD3@qS6l-=uKv~- zNq5&RA-${l#>#c)@X>aE9w-=T$`UE=q2WNI2pg}RduH5WIDbUJQMNPqfHwG&9#*+k zuSo9+?MJaEH6o7C+NAtUuc{05q{I$dz*_81XfAf$1@f`bkNp5=ukp?lC?aNZ!MQ5V zS#%ORY`(;t(R0N}jT|453b3^1)9r`;nV}aLGSH<74K1E42(a9Xq}dIC}h6kq1Lc$`*U7+6dwG zCV%z_b~!y;&}R?!98Is#XQHbnRFtFR8F=9E&ZjFp* zMrk!c%0#!W;`a}TwuQ8TWi;?fpi8fygoGb;j}C0BK97;z(dT(WDj!82<|4i(^vv!l zV!5$t3(e2#B4jeC1Q~qw`=|>b*!?{iIf6O*BVib{DxBK$QLK}QF(Z-hkBifbbv36V zWUs~#5?wXh>L!>&-*iM}(?VEFrv18K=gou($_*hQ{K(QZoSDM8tcr1=;lNXGwk<$U z_X#1B&@kpoP}Py1LdiZM9?bZs=Yd%fshA^0-@+MM70yZ(@t|S;W;C+Lk3A>eVU7HP zxgwnMKPbgS1Z#&QSv917!7{y;16oM77P(bZf2O99p1Y!Y`kzPl^R6DwkNf_esf}@u zc%#U$QRhmh;9BFdGxA5sKBjC_kulJQE`jWQPuio!;U_v_2-nbL>lChb(k9V4288Oi zuYqZdj&18wMUguh zyL&OPU6W-xP)`c?zIQe~c{R=!mXiPvcMk7OTv(ye*eMHl3Cf^qFTO|V<#gaQ;>t<> z35mkQ*F8Dh1Y1XnH*T9DG|dCom&33pJs|1BNqZMQ7X55C6Wxw+*a*J995%7S_&0hm z=1&WUf*e3<=P`K1YSCT3AW+D1S#)gOO;KBA%hSW7Dwg~`nF;Wos7ZAGdwz(OyC%8R zEo}$sL7MkUO}PAZq}%`xL$II^IeJF3s)q`C;UYr9ByhWe6!0|);0CZ<^ab!N8$nW` z$<;>-wJJwL<;#J1mz?r1@06IjxFhPhETCnY2-&7D*y|F0uP}kOFboC=Duzgg_YDFI z1pqK)1_>&LNQU&R|G&$iHr-Lm7>L1I&Zk%3VcJmJ%B+ZG$*$&6Q9SiWF}o4 zi#5}Va45*$mlV1voMTf}W+-g8tR&BXvzjKfrsdxP0zd!)0YESe1_&yKNQUQvw1&00IFZFboC=Duzgg_YDFI1pqJ}1_@w>NC9O71OYEF5d;i!`Q8P& zkey}g)oC*V0SE+w1zMrhQa4}%1bsj@8!PudnS~t)C(wh6pkT7}`-zzT9qEnmD5&3( zjr?0`YtXjLg;1$kZjx421F2o?6mKBA~7DT)IgRsJ@_b^7b~4K*!wIV)9p^INm0Ww z>Q?lVP5Uv7&&?PUL^|BU9teD72y7@b2G^dANawAX!oXBHXZY7WF#Uke<$G;z#ynhz zD*Ws7TUCOdpG+^d@L^3=&Sy&hsb-Qj?sGpdIbI78NUO&+g%$|z2g~#>QiO<6J6koc ze2Kh0hZi3FszR^)+tLB&9~Q;tpNk*@fEx-h3@Kf6ME|oCYWJ^I!ZZf<(K76xG=u4% zk$C%EaO~t3e{R^`4}J(9)D35Os}gzr8py@JKr^jjhXBNUp43TDk0qzU1+Y&pd@@wu zq^X6q6s9v4d9A0d5tK$vYpZnM8f+**95Sfbe)D}7I$Jz5foc25s_9LD904(sJ~v#k zq`qO{`|zms#ZN>WrYth`6=j^x8e`sBjvBmNQLRnmr@li8CVBYZN{?K@E^wRCFsEHa z+^MM)_HE>A-=-2sPQwtwbjcK$Zw-~clZ1A^k%IJB5VzH0@Z|&i zBP=ptP$?!BFDcUzP5Zi({yws`Y1l?9XU)N6{XZ%L&Vfa-_*#z3HVbV-HQs5k2>-KF z$;{oghTBD&{TG{ao|a!P4g_qp<#P@gDSa!IumML|3?4>n40o4yJ`k-i}M! z7>ygr4K`qPnhe>Lt)HHcUzbqg54*3}7ofN15iPgr~*+Jb~{7F$pR zLy20-Xeld#7RCh<0=-U3pW>E~QzV4A+piHV4kq=nfDtc-3aM+aX-deYq9l1 zt%9vd_*NFpPc-Use5}n6kvaNLela2D1KJh%Vv5Dt&QI~h(XmG@?oBMYqs()#xY@BY ze*I>eQ#p8zDJ-7gH<6`e_fW-S`^#zKf_>#JPd=Rr4|ALKmY;(Krjpj2r7n1hW8Bu3k3iKK#KSU z9=fpAjY);E5uSb*{D2o@eW0>NlP_h5Mjo55?aEaxbwhpTMPC{>?K?ev1cI{03x>$Y Mv2DRKTh_i}^|O5=`Tzg` literal 0 HcmV?d00001 diff --git a/src/test/resources/tls/client-truststore.bcfks b/src/test/resources/tls/client-truststore.bcfks new file mode 100644 index 0000000000000000000000000000000000000000..8373ba68061dce13e7620cc3bae65beea7665282 GIT binary patch literal 1718 zcmV;n21)raf(EiMf(7+3fs_UbDuzgg_YDCB4KRU*Fk}V^Duzgg_YDCB3@}#&K%uLt z$FBSE3^1%9VO?PXncgkNC9O71OYEF5d;jDnfR(T z{A?{sxyz~o0SE+w1zJ5>m=^W!ZRQl1$n!xk2#BP>HRL(xLw**M-9y1(A-khroMdRb zfX7m{=U_$NML6yJFlR$RtRw$8ZsHg-0p!31YB~O zTThgWCJ;2wHw3pbrH2TVgC?fuQ9B9IKi7^*9CnG#draKV%s6^cMDypaw!ljwC9IOZ zmz2W}*2wBeI3TgJAv4E`6O20P7G7>W`u}Bxr#yAcTG*EKm!p^Pbd&wLPuu()6M*6~ z6ah2$iYB;KFE_}eR6|rN6hx}W#B1xu6I3c>pfPg}RnBj{enqfeU6la_LeFc$s_}DZc%!bzQe&aSU+0{zx3cq ze1XFtpRmE)8+=VV9Mj2LfHzJ6)wO4Kb!+;kcMfnQB``X6(!^aNtic*51$?& zc5q7Se`|)Qkxt(ou5@xf&-xY2A9%J)A`=4$0AqN#>582lXY}N^Q0xSfxdj8EIfhic zIhmA+IW`C1*9QIh*;u zMgcszmSmWXdf>;2RyDX+z6e`+sj(w(EtE-qh9XG_iCg?yIMICHUXR9#??^vGK!1~NLJ1%wYnQl&l zbaS5=Fx>M8(PN1Pp5E0GlPyg|eXw(y#{;V|XMAKR6@-R>Ky16+U8;_*xE5qoMGOhs zm&L=nW`8=V`J@CJ?7ggIPW~2 zB=a|K0>Y@hxdAiuPpelox44OjFhpf@OxXoAY;smc<7rigvvUfVhM8bIy45tOOk@HT zxuJa(IaDpei7Vg3p!B{*=rS9;u;=*!Sh62Sxm!weiw~4T`B?sKaT5>a-8PF#Vx0{O zG01Cwb)V+Oj|V~aZvq0hzy@vQXlKlkK7Qf_@l!=#1AgKJ;0PB1b9R!xp4$3L%gTuc|z|2*6pD`a=%}A27)`=Tpfef_#zN+yJ_)$sGll z2js>)KqEGhPCr@Ug{_xq6Kg_66T=3SSLhL+(oGp*32Gj$!am`vBDYB=cOYt|1#1no1(551yEw5iH5(!nFFoCu(3WR5?^trcs^N z-a6@-J(7>1^%G-nMMM+ub6y1Q&*(8GSQ7#QKmY;(Krjpj2r7n1hW8Bu3k3iKK+}~@ zj0oLfGiH0f6bC;6s;o$7o$X9khvKcq;~*gDfM!Fc&a_A0kU6$7v||pr4Ri;oly)E| MOC^Ye;%~^E51PRc!vFvP literal 0 HcmV?d00001 diff --git a/src/test/resources/tls/client-truststore.jks b/src/test/resources/tls/client-truststore.jks new file mode 100644 index 0000000000000000000000000000000000000000..7608c0b767e3efb775bf4fcc13add1be0a4a41f7 GIT binary patch literal 1313 zcmezO_TO6u1_mY|W(3o$xs}lb@WJlaXIs z0uy7$BF2S9j2nv>Gm@BroH(zMp@Er^g`tIsk%4g(m}_Zd2IUTflbV>F44Rls+1Rz( zJkD9LFakLmOihf84E>d+H+QajxqtQBj;iyXf!jXo9i3;r-dy6vt0U9o?f#mvJ$DXV zc|^k4atG)0L+fOMXD@e;ZoMG5cE^^=_EOK5%$PNN{UV#qI5ZaN|56v^vQ1h!+0}$| z!N1HLw}>C!cNH4vm~$==2;Vq$?O6t8+g%|o+cf3pru6-2c4;f0KIaX~7L#Rb^h#gO zh<#+cK~w*rV9)$ta~m6<8~1LXwB6wP&c~jS`Wc)vibO3%U)g4Ny9FOJcI|JlHd=D% z!Kb1Ls(F6)UDg~H3y%amdDtVRxw!Uz+(PGj-f90?CfHp)FQ)u3;!685j+ga{GB;#T zDWA@>U{C#_^w?>ihYxF+rDcN5wR9#~hF#yLEo-g#e*fO{U+E{ykGH-z+GM=zX~Tg% zS2JUQVZv-g&_8}w@?yj(Kv^3vGg=+}Q-uY8mIW^em;ce|zPp-(Cg$_+JhSG2#8 zbNBdB_dEXH_K+6CY$c<6PlNBSXA;!rm1nwTFx^PypZdC6-E+M)m2U3pemw8yL*`{R zL5n!&0z4+~W%uS4}44{BW_bPraYosQBm^YQ*ddoJe=!nz?wztJ&|9eX*orcG9Uit;V`ilcXj{K4g`bl6v;- zhvv?i@h11&SB6weI_7^iYGcf}xLWtM*$z34bxUHbXF6??>OA9wO* zU2BlA4d1zS-jgr6|4kJfv>McU!F z$;Xtc-yO{oy7%$LQ&UfKw9<#!k-@+Yn8aF)m5UF4U&Ho>r)l>ZUngs?v+djb);^W_ z{i|6UC_U@sPT3U}^D~WB%7n_IQ`3OulY3V|3;;E J53vL#000c71^xg4 literal 0 HcmV?d00001 diff --git a/src/test/resources/tls/client.ks.bcfks b/src/test/resources/tls/client.ks.bcfks new file mode 100644 index 0000000000000000000000000000000000000000..18f3b4429025e82151a0aca27a73b290565f54c9 GIT binary patch literal 2750 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 P{cNIg@hW=gHGumIc0Be5 literal 0 HcmV?d00001 diff --git a/src/test/resources/tls/client.ts.bcfks b/src/test/resources/tls/client.ts.bcfks new file mode 100644 index 0000000000000000000000000000000000000000..18f4880a25f03a33f91a013271c1a1dabb7cfb35 GIT binary patch literal 1359 zcmV-V1+e-sf(1)3f&`8*fs_UbDuzgg_YDCB4KRU*Fk}V^Duzgg_YDCB3@}#&K&{QU zar&KGbF3>?rG+!S!G2Z+96NC9O71OYEF5d;hc2)dD} zO+>;Cd8g(A0SE+w1M}sDo@y;*D8o>#T4{-BP_ykWM+=h6`9e^$kP zgnnWRU;18>6(sPEUP5!`;lMx*D*w<*k?a%20?N$RXdl2zDZrkjII*wd>@v42UUz*(_X?;-o^F49`bM7@Xm8B) zIp=j!kJ&iEzXFUy|0cnJ8YXB(+OsrD;d?halKWm4I2WdspPyTuI&oztW)G+sGs>A5 z32`naA<2{kuy$r$vB`K|+fKA+$p))-kozVP6dzX;mdrDV;iV@MsRmry#{z3KTfbK$ zZB!xKezENsF-1{!c{V349nq}{1>ctCpm^H#RMF(YgnqX}CyD)VR)*YA4@fP=uMPB9 zAGtQ(M#3ew*DN_cQ&}k_>^?u?HI%ZS9()u8r-b|!@ENlk=q`TUo6Jr z|8J%jcYp_ohVtz97Zb=9?r9&{HI9rDGxg#E!6um}=S?-_XLP6i_7n<91-^e6J_j}L z_T-1BA6)!~T8D&oRQ~Z4@n*-xk>vzo)&73_pW&Nj0^N^*!~gFD&l-cj>4*?>p6O4U zL34LPN<4d|w2=R<)G_7mGC?eR(cSltmrSAQ;nuWS>pIog4>`=Bp4p;I5<;LP(o}C} z?$b6`2!tohu2I7+wZJ?yo8Q-Xwjdcj3FG^P#Vl!e>ju{i zog}Pq0`4Vz#c^0Dp8gii=b8y!hs-1BwJliEfORUbG`(dVFUj{8@*QrD;Yo5L322ei zt5_r>IL{LjT2`0nh=D^cfs;Y<<9J!MQ9OtUunJm41A;dRyYdUTi52pWx0oDglO8$1 zzBl)ULK7Us_p1n8;$5*|GPtutrOOz-DcR~|$AQ8*qDWXYZ(Tn%zr@#N81PV-Yca<- zm3O&zl!&D@dRq!dLXT zPYkgFf>uo`x6H4qPEz64PjGZ_ly>yrH)U&+XCX(Mt@1*b{l16s` zB~tOY(Sy8Ne$%rg7LN=>O;k(I35GQn!g!W-C{sl^xgM|W?l6J2FboC=Duzgg_YDFI z1pqK)1_>&LNQU&R|G&}mwT*N_yz$?o?iNH5aQ?^p=K!xEs3)D4AfZ;OaOJZ zkrUbla>!hPR`K0dDVenpHV7UwYqIfT=7MA+>FSXUd7c0O literal 0 HcmV?d00001 diff --git a/src/test/resources/tls/client.ts.jks b/src/test/resources/tls/client.ts.jks new file mode 100644 index 0000000000000000000000000000000000000000..e71638cad7abf8bf237e0356f3e759765172dc7c GIT binary patch literal 954 zcmezO_TO6u1_mY|W(3o0Nk#eDsYO6;+JRV2F$UHMJyQcq1_tJ8gC^#3gC?f<1+AKTV9PBZ4lX@4$Mw&ohcj#+Mp~w> zc0Q={UMnOw)NlRW_*WYlwjr$cz9x%4`f2SNg3w}gebFWZ=_8ZXbj@oyR5RrP6VcfKv?Hv9Uv zvHYY_oe{T0dPK&0@zC=w(?gama=0&M-qt_$wco@JufUy)Ez6%V-YD?ziw6Tim7b*>vvz5nfb+7 zqfAZ*IS_$q3K)ot3@)oPep_x?f9n8W)JEJSW#w}~6wCb=b=REe`^=CuD=|zRb zwHLN_r$37S+qThGO)5M5kn6FW+7&C-RVmx6MGBqGF#q)T`JWYm_GUU}kEQ>ytu?w0MO7{#KDJG%wLpKh1^c*knC=_b$J xv(ja!zM1EJc5mFmP_D$ycOQx!*(Rru^K6=Db8+y!eO`}FKNn;d7V*^J1pwgYVCnz> literal 0 HcmV?d00001 diff --git a/src/test/resources/tls/genericConnectionTests.bcfks b/src/test/resources/tls/genericConnectionTests.bcfks new file mode 100644 index 0000000000000000000000000000000000000000..373066a40d5c427327c3efb91f0e9f0c05ef703e GIT binary patch literal 3525 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 v%CwD|^qy>V3zuGF4QV0(Z?u+_A5a)Hk|aqY Date: Tue, 12 Nov 2024 13:55:29 -0300 Subject: [PATCH 2/4] W-16889209: Changes to be FIPS compatible --- src/test/munit/activemq-over-ssl-test-case.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/munit/activemq-over-ssl-test-case.xml b/src/test/munit/activemq-over-ssl-test-case.xml index db1b0969..543a0510 100644 --- a/src/test/munit/activemq-over-ssl-test-case.xml +++ b/src/test/munit/activemq-over-ssl-test-case.xml @@ -42,14 +42,14 @@ - + - + @@ -96,8 +96,8 @@ ignore="#[p('mule.security.model')==null or p('mule.security.model')!='fips140-2']" expectedException="java.security.KeyStoreException"> - - + + From ec26e94be6626ff623c079b1bf0c1010b82fb6f0 Mon Sep 17 00:00:00 2001 From: Sorin Date: Wed, 29 Jan 2025 13:31:23 +0200 Subject: [PATCH 3/4] W-16889209 | merge changes --- pom.xml | 60 ++ .../activemq/transport/tcp/SslTransport.java | 179 ++++ .../activemq/transport/tcp/TcpTransport.java | 767 ++++++++++++++ .../activemq/ActiveMQConnectionProvider.java | 9 + .../provider/loader/FirewallLoader.java | 13 + src/test/docker/tls/Dockerfile | 10 +- src/test/docker/tls/activemq.xml | 6 +- src/test/docker/tls/broker-keystore.ks | Bin 1993 -> 3742 bytes src/test/docker/tls/client-truststore.ks | Bin 1313 -> 3743 bytes src/test/docker/tls/java.security.fips | 955 ++++++++++++++++++ .../munit/activemq-over-ssl-test-case.xml | 28 +- ...mq-ssl-listener-reconnection-test-case.xml | 5 +- .../munit/xa/activemq-ssl-xa-test-case.xml | 5 +- src/test/resources/activemq-fips.xml | 12 +- src/test/resources/activemq.xml | 2 +- src/test/resources/tls/broker.bcfks | Bin 0 -> 3742 bytes src/test/resources/tls/client.bcfks | Bin 0 -> 3743 bytes 17 files changed, 2030 insertions(+), 21 deletions(-) create mode 100644 src/main/java/org/apache/activemq/transport/tcp/SslTransport.java create mode 100644 src/main/java/org/apache/activemq/transport/tcp/TcpTransport.java create mode 100644 src/main/java/org/mule/extensions/jms/internal/connection/provider/loader/FirewallLoader.java create mode 100644 src/test/docker/tls/java.security.fips create mode 100644 src/test/resources/tls/broker.bcfks create mode 100644 src/test/resources/tls/client.bcfks diff --git a/pom.xml b/pom.xml index 2d984973..0907b81f 100644 --- a/pom.xml +++ b/pom.xml @@ -234,6 +234,63 @@ + + org.apache.maven.plugins + maven-surefire-plugin + 2.19.1 + + -Dfile.encoding=UTF-8 -javaagent:${settings.localRepository}/org/aspectj/aspectjweaver/${aspectjVersion}/aspectjweaver-${aspectjVersion}.jar -javaagent:${settings.localRepository}/org/jacoco/org.jacoco.agent/${jacoco.version}/org.jacoco.agent-${jacoco.version}-runtime.jar=destfile='${session.executionRootDirectory}/target/jacoco.exec' + + + listener + io.qameta.allure.junit4.AllureJunit4 + + + + + ${java.io.tmpdir}/mule/freePortFinder + ${project.version} + ${activemq.listener.port} + ${activemq.ssl.listener.port} + ${project.build.directory} + + + + allure.results.directory + ${project.build.directory}/allure-results + + + 1 + false + ${project.build.directory} + + + + org.aspectj + aspectjweaver + ${aspectjVersion} + + + org.jacoco + org.jacoco.agent + ${jacoco.version} + runtime + + + + javax.xml.bind + jaxb-api + 2.3.1 + + + + + org.glassfish.jaxb + jaxb-runtime + 2.3.1 + + + com.mycila license-maven-plugin @@ -366,6 +423,9 @@ + + true + -javaagent:${settings.localRepository}/org/jacoco/org.jacoco.agent/${jacoco.version}/org.jacoco.agent-${jacoco.version}-runtime.jar=destfile=${session.executionRootDirectory}/target/jacoco-munit.exec diff --git a/src/main/java/org/apache/activemq/transport/tcp/SslTransport.java b/src/main/java/org/apache/activemq/transport/tcp/SslTransport.java new file mode 100644 index 00000000..548fab0f --- /dev/null +++ b/src/main/java/org/apache/activemq/transport/tcp/SslTransport.java @@ -0,0 +1,179 @@ +package org.apache.activemq.transport.tcp; + +import java.io.IOException; +import java.net.Socket; +import java.net.SocketException; +import java.net.URI; +import java.net.UnknownHostException; +import java.security.cert.X509Certificate; +import java.util.Collections; + +import javax.net.ssl.SNIHostName; +import javax.net.ssl.SSLParameters; +import javax.net.ssl.SSLPeerUnverifiedException; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; + +import org.apache.activemq.command.ConnectionInfo; +import org.apache.activemq.wireformat.WireFormat; +public class SslTransport extends TcpTransport { + + /** + * Default to null as there are different defaults between server and client, initialiseSocket + * for more details + */ + private Boolean verifyHostName = null; + + /** + * Connect to a remote node such as a Broker. + * + * @param wireFormat The WireFormat to be used. + * @param socketFactory The socket factory to be used. Forcing SSLSockets + * for obvious reasons. + * @param remoteLocation The remote location. + * @param localLocation The local location. + * @param needClientAuth If set to true, the underlying socket will need + * client certificate authentication. + * @throws UnknownHostException If TcpTransport throws. + * @throws IOException If TcpTransport throws. + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + public SslTransport(WireFormat wireFormat, SSLSocketFactory socketFactory, URI remoteLocation, URI localLocation, boolean needClientAuth) throws IOException { + super(wireFormat, socketFactory, remoteLocation, localLocation); + if (this.socket != null) { + ((SSLSocket)this.socket).setNeedClientAuth(needClientAuth); + } + } + + @Override + protected void initialiseSocket(Socket sock) throws SocketException, IllegalArgumentException { + /** + * This needs to default to null because this transport class is used for both a server transport + * and a client connection and we have different defaults for both. + * If we default it to a value it might override the transport server setting + * that was configured inside TcpTransportServer (which sets a default to false for server side) + * + * The idea here is that if this is a server transport then verifyHostName will be set by the setter + * and not be null as TcpTransportServer will set a default value of false (or a user will set it + * using transport.verifyHostName) but if this is a client connection the value will be null by default + * and will stay null if the user uses socket.verifyHostName to set the value or doesn't use the setter + * If it is null then we can check socketOptions for the value and if not set there then we can + * just set a default of true as this will be a client + * + * Unfortunately we have to do this to stay consistent because every other SSL option on the client + * side can be configured using socket. but this particular option isn't actually part of the socket + * so it makes it tricky from a user standpoint. For consistency sake I think it makes sense to allow + * using the socket. prefix that has been established so users do not get confused (as well as + * allow using no prefix which just calls the setter directly) + * + * Because of this there are actually two ways a client can configure this value, the client can either use + * socket.verifyHostName= as mentioned or just simply use verifyHostName= without using the socket. + * prefix and that will also work as the value will be set using the setter on the transport + * + * example server transport config: + * ssl://localhost:61616?transport.verifyHostName=true + * + * example from client: + * ssl://localhost:61616?verifyHostName=true + * OR + * ssl://localhost:61616?socket.verifyHostName=true + * + */ + if (verifyHostName == null) { + //Check to see if the user included the value as part of socket options and if so then use that value + if (socketOptions != null && socketOptions.containsKey("verifyHostName")) { + verifyHostName = Boolean.parseBoolean(socketOptions.get("verifyHostName").toString()); + socketOptions.remove("verifyHostName"); + } else { + //If null and not set then this is a client so default to true + verifyHostName = true; + } + } + + // Lets try to configure the SSL SNI field. Handy in case your using + // a single proxy to route to different messaging apps. + final SSLParameters sslParams = new SSLParameters(); + if (remoteLocation != null) { + sslParams.setServerNames(Collections.singletonList(new SNIHostName(remoteLocation.getHost()))); + } + + if (verifyHostName) { + sslParams.setEndpointIdentificationAlgorithm("HTTPS"); + } + + if (remoteLocation != null || verifyHostName) { + // AMQ-8445 only set SSLParameters if it has been populated before + ((SSLSocket) this.socket).setSSLParameters(sslParams); + } + + super.initialiseSocket(sock); + } + + /** + * Initialize from a ServerSocket. No access to needClientAuth is given + * since it is already set within the provided socket. + * + * @param wireFormat The WireFormat to be used. + * @param socket The Socket to be used. Forcing SSL. + * @throws IOException If TcpTransport throws. + */ + public SslTransport(WireFormat wireFormat, SSLSocket socket) throws IOException { + super(wireFormat, socket); + } + + public SslTransport(WireFormat format, SSLSocket socket, + InitBuffer initBuffer) throws IOException { + super(format, socket, initBuffer); + } + + /** + * Overriding in order to add the client's certificates to ConnectionInfo + * Commmands. + * + * @param command The Command coming in. + */ + @Override + public void doConsume(Object command) { + // The instanceof can be avoided, but that would require modifying the + // Command clas tree and that would require too much effort right + // now. + if (command instanceof ConnectionInfo) { + ConnectionInfo connectionInfo = (ConnectionInfo)command; + connectionInfo.setTransportContext(getPeerCertificates()); + } + super.doConsume(command); + } + + public void setVerifyHostName(Boolean verifyHostName) { + this.verifyHostName = verifyHostName; + } + + /** + * @return peer certificate chain associated with the ssl socket + */ + @Override + public X509Certificate[] getPeerCertificates() { + + SSLSocket sslSocket = (SSLSocket)this.socket; + + SSLSession sslSession = sslSocket.getSession(); + + X509Certificate[] clientCertChain; + try { + clientCertChain = (X509Certificate[])sslSession.getPeerCertificates(); + } catch (SSLPeerUnverifiedException e) { + clientCertChain = null; + } + + return clientCertChain; + } + + /** + * @return pretty print of 'this' + */ + @Override + public String toString() { + return "ssl://" + socket.getInetAddress() + ":" + socket.getPort(); + } +} \ No newline at end of file diff --git a/src/main/java/org/apache/activemq/transport/tcp/TcpTransport.java b/src/main/java/org/apache/activemq/transport/tcp/TcpTransport.java new file mode 100644 index 00000000..069deeb9 --- /dev/null +++ b/src/main/java/org/apache/activemq/transport/tcp/TcpTransport.java @@ -0,0 +1,767 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF 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 org.apache.activemq.transport.tcp; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InterruptedIOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.SocketAddress; +import java.net.SocketException; +import java.net.SocketTimeoutException; +import java.net.URI; +import java.net.UnknownHostException; +import java.nio.ByteBuffer; +import java.security.cert.X509Certificate; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; + +import javax.net.SocketFactory; + +import org.apache.activemq.Service; +import org.apache.activemq.TransportLoggerSupport; +import org.apache.activemq.thread.TaskRunnerFactory; +import org.apache.activemq.transport.Transport; +import org.apache.activemq.transport.TransportThreadSupport; +import org.apache.activemq.util.InetAddressUtil; +import org.apache.activemq.util.IntrospectionSupport; +import org.apache.activemq.util.ServiceStopper; +import org.apache.activemq.wireformat.WireFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * An implementation of the {@link Transport} interface using raw tcp/ip + */ +public class TcpTransport extends TransportThreadSupport implements Transport, Service, Runnable { + + private static final Logger LOG = LoggerFactory.getLogger(TcpTransport.class); + + protected final URI remoteLocation; + protected final URI localLocation; + protected final WireFormat wireFormat; + + protected int connectionTimeout = 30000; + protected int soTimeout; + protected int socketBufferSize = 64 * 1024; + protected int ioBufferSize = 8 * 1024; + protected boolean closeAsync=true; + protected Socket socket; + protected DataOutputStream dataOut; + protected DataInputStream dataIn; + protected TimeStampStream buffOut = null; + + protected final InitBuffer initBuffer; + + /** + * The Traffic Class to be set on the socket. + */ + protected int trafficClass = 0; + /** + * Keeps track of attempts to set the Traffic Class on the socket. + */ + private boolean trafficClassSet = false; + /** + * Prevents setting both the Differentiated Services and Type of Service + * transport options at the same time, since they share the same spot in + * the TCP/IP packet headers. + */ + protected boolean diffServChosen = false; + protected boolean typeOfServiceChosen = false; + /** + * trace=true -> the Transport stack where this TcpTransport + * object will be, will have a TransportLogger layer + * trace=false -> the Transport stack where this TcpTransport + * object will be, will NOT have a TransportLogger layer, and therefore + * will never be able to print logging messages. + * This parameter is most probably set in Connection or TransportConnector URIs. + */ + protected boolean trace = false; + /** + * Name of the LogWriter implementation to use. + * Names are mapped to classes in the resources/META-INF/services/org/apache/activemq/transport/logwriters directory. + * This parameter is most probably set in Connection or TransportConnector URIs. + */ + protected String logWriterName = TransportLoggerSupport.defaultLogWriterName; + /** + * Specifies if the TransportLogger will be manageable by JMX or not. + * Also, as long as there is at least 1 TransportLogger which is manageable, + * a TransportLoggerControl MBean will me created. + */ + protected boolean dynamicManagement = false; + /** + * startLogging=true -> the TransportLogger object of the Transport stack + * will initially write messages to the log. + * startLogging=false -> the TransportLogger object of the Transport stack + * will initially NOT write messages to the log. + * This parameter only has an effect if trace == true. + * This parameter is most probably set in Connection or TransportConnector URIs. + */ + protected boolean startLogging = true; + /** + * Specifies the port that will be used by the JMX server to manage + * the TransportLoggers. + * This should only be set in an URI by a client (producer or consumer) since + * a broker will already create a JMX server. + * It is useful for people who test a broker and clients in the same machine + * and want to control both via JMX; a different port will be needed. + */ + protected int jmxPort = 1099; + protected boolean useLocalHost = false; + protected int minmumWireFormatVersion; + protected SocketFactory socketFactory; + protected final AtomicReference stoppedLatch = new AtomicReference(); + protected volatile int receiveCounter; + + protected Map socketOptions; + private int soLinger = Integer.MIN_VALUE; + private Boolean keepAlive; + private Boolean tcpNoDelay; + private Thread runnerThread; + + /** + * Connect to a remote Node - e.g. a Broker + * + * @param wireFormat + * @param socketFactory + * @param remoteLocation + * @param localLocation - e.g. local InetAddress and local port + * @throws IOException + * @throws UnknownHostException + */ + public TcpTransport(WireFormat wireFormat, SocketFactory socketFactory, URI remoteLocation, + URI localLocation) throws UnknownHostException, IOException { + this.wireFormat = wireFormat; + this.socketFactory = socketFactory; + try { + this.socket = socketFactory.createSocket(); + } catch (SocketException e) { + this.socket = null; + } + this.remoteLocation = remoteLocation; + this.localLocation = localLocation; + this.initBuffer = null; + setDaemon(false); + } + + /** + * Initialize from a server Socket + * + * @param wireFormat + * @param socket + * @throws IOException + */ + public TcpTransport(WireFormat wireFormat, Socket socket) throws IOException { + this(wireFormat, socket, null); + } + + public TcpTransport(WireFormat wireFormat, Socket socket, InitBuffer initBuffer) throws IOException { + this.wireFormat = wireFormat; + this.socket = socket; + this.remoteLocation = null; + this.localLocation = null; + this.initBuffer = initBuffer; + setDaemon(true); + } + + /** + * A one way asynchronous send + */ + @Override + public void oneway(Object command) throws IOException { + checkStarted(); + wireFormat.marshal(command, dataOut); + dataOut.flush(); + } + + /** + * @return pretty print of 'this' + */ + @Override + public String toString() { + return "" + (socket.isConnected() ? "tcp://" + socket.getInetAddress() + ":" + socket.getPort() + "@" + socket.getLocalPort() + : (localLocation != null ? localLocation : remoteLocation)) ; + } + + /** + * reads packets from a Socket + */ + @Override + public void run() { + LOG.trace("TCP consumer thread for " + this + " starting"); + this.runnerThread=Thread.currentThread(); + try { + while (!isStopped() && !isStopping()) { + doRun(); + } + } catch (IOException e) { + stoppedLatch.get().countDown(); + onException(e); + } catch (Throwable e){ + stoppedLatch.get().countDown(); + IOException ioe=new IOException("Unexpected error occurred: " + e); + ioe.initCause(e); + onException(ioe); + }finally { + stoppedLatch.get().countDown(); + } + } + + protected void doRun() throws IOException { + try { + Object command = readCommand(); + doConsume(command); + } catch (SocketTimeoutException e) { + } catch (InterruptedIOException e) { + } + } + + protected Object readCommand() throws IOException { + return wireFormat.unmarshal(dataIn); + } + + // Properties + // ------------------------------------------------------------------------- + public String getDiffServ() { + // This is the value requested by the user by setting the Tcp Transport + // options. If the socket hasn't been created, then this value may not + // reflect the value returned by Socket.getTrafficClass(). + return Integer.toString(this.trafficClass); + } + + public void setDiffServ(String diffServ) throws IllegalArgumentException { + this.trafficClass = QualityOfServiceUtils.getDSCP(diffServ); + this.diffServChosen = true; + } + + public int getTypeOfService() { + // This is the value requested by the user by setting the Tcp Transport + // options. If the socket hasn't been created, then this value may not + // reflect the value returned by Socket.getTrafficClass(). + return this.trafficClass; + } + + public void setTypeOfService(int typeOfService) { + this.trafficClass = QualityOfServiceUtils.getToS(typeOfService); + this.typeOfServiceChosen = true; + } + + public boolean isTrace() { + return trace; + } + + public void setTrace(boolean trace) { + this.trace = trace; + } + + public String getLogWriterName() { + return logWriterName; + } + + public void setLogWriterName(String logFormat) { + this.logWriterName = logFormat; + } + + public boolean isDynamicManagement() { + return dynamicManagement; + } + + public void setDynamicManagement(boolean useJmx) { + this.dynamicManagement = useJmx; + } + + public boolean isStartLogging() { + return startLogging; + } + + public void setStartLogging(boolean startLogging) { + this.startLogging = startLogging; + } + + public int getJmxPort() { + return jmxPort; + } + + public void setJmxPort(int jmxPort) { + this.jmxPort = jmxPort; + } + + public int getMinmumWireFormatVersion() { + return minmumWireFormatVersion; + } + + public void setMinmumWireFormatVersion(int minmumWireFormatVersion) { + this.minmumWireFormatVersion = minmumWireFormatVersion; + } + + public boolean isUseLocalHost() { + return useLocalHost; + } + + /** + * Sets whether 'localhost' or the actual local host name should be used to + * make local connections. On some operating systems such as Macs its not + * possible to connect as the local host name so localhost is better. + */ + public void setUseLocalHost(boolean useLocalHost) { + this.useLocalHost = useLocalHost; + } + + public int getSocketBufferSize() { + return socketBufferSize; + } + + /** + * Sets the buffer size to use on the socket + */ + public void setSocketBufferSize(int socketBufferSize) { + this.socketBufferSize = socketBufferSize; + } + + public int getSoTimeout() { + return soTimeout; + } + + /** + * Sets the socket timeout + */ + public void setSoTimeout(int soTimeout) { + this.soTimeout = soTimeout; + } + + public int getConnectionTimeout() { + return connectionTimeout; + } + + /** + * Sets the timeout used to connect to the socket + */ + public void setConnectionTimeout(int connectionTimeout) { + this.connectionTimeout = connectionTimeout; + } + + public Boolean getKeepAlive() { + return keepAlive; + } + + /** + * Enable/disable TCP KEEP_ALIVE mode + */ + public void setKeepAlive(Boolean keepAlive) { + this.keepAlive = keepAlive; + } + + /** + * Enable/disable soLinger + * @param soLinger enabled if > -1, disabled if == -1, system default otherwise + */ + public void setSoLinger(int soLinger) { + this.soLinger = soLinger; + } + + public int getSoLinger() { + return soLinger; + } + + public Boolean getTcpNoDelay() { + return tcpNoDelay; + } + + /** + * Enable/disable the TCP_NODELAY option on the socket + */ + public void setTcpNoDelay(Boolean tcpNoDelay) { + this.tcpNoDelay = tcpNoDelay; + } + + /** + * @return the ioBufferSize + */ + public int getIoBufferSize() { + return this.ioBufferSize; + } + + /** + * @param ioBufferSize the ioBufferSize to set + */ + public void setIoBufferSize(int ioBufferSize) { + this.ioBufferSize = ioBufferSize; + } + + /** + * @return the closeAsync + */ + public boolean isCloseAsync() { + return closeAsync; + } + + /** + * @param closeAsync the closeAsync to set + */ + public void setCloseAsync(boolean closeAsync) { + this.closeAsync = closeAsync; + } + + // Implementation methods + // ------------------------------------------------------------------------- + protected String resolveHostName(String host) throws UnknownHostException { + if (isUseLocalHost()) { + String localName = InetAddressUtil.getLocalHostName(); + if (localName != null && localName.equals(host)) { + return "localhost"; + } + } + return host; + } + + /** + * Configures the socket for use + * + * @param sock the socket + * @throws SocketException, IllegalArgumentException if setting the options + * on the socket failed. + */ + protected void initialiseSocket(Socket sock) throws SocketException, IllegalArgumentException { + if (socketOptions != null) { + // copy the map as its used values is being removed when calling setProperties + // and we need to be able to set the options again in case socket is re-initailized + Map copy = new HashMap(socketOptions); + IntrospectionSupport.setProperties(socket, copy); + if (!copy.isEmpty()) { + throw new IllegalArgumentException("Invalid socket parameters: " + copy); + } + } + + try { + //only positive values are legal + if (socketBufferSize > 0) { + sock.setReceiveBufferSize(socketBufferSize); + sock.setSendBufferSize(socketBufferSize); + } else { + LOG.warn("Socket buffer size was set to {}; Skipping this setting as the size must be a positive number.", socketBufferSize); + } + } catch (SocketException se) { + LOG.warn("Cannot set socket buffer size = " + socketBufferSize); + LOG.debug("Cannot set socket buffer size. Reason: " + se.getMessage() + ". This exception is ignored.", se); + } + sock.setSoTimeout(soTimeout); + + if (keepAlive != null) { + sock.setKeepAlive(keepAlive.booleanValue()); + } + + if (soLinger > -1) { + sock.setSoLinger(true, soLinger); + } else if (soLinger == -1) { + sock.setSoLinger(false, 0); + } + if (tcpNoDelay != null) { + sock.setTcpNoDelay(tcpNoDelay.booleanValue()); + } + if (!this.trafficClassSet) { + this.trafficClassSet = setTrafficClass(sock); + } + } + + @Override + protected void doStart() throws Exception { + connect(); + stoppedLatch.set(new CountDownLatch(1)); + super.doStart(); + } + + protected void connect() throws Exception { + + if (socket == null && socketFactory == null) { + throw new IllegalStateException("Cannot connect if the socket or socketFactory have not been set"); + } + + InetSocketAddress localAddress = null; + InetSocketAddress remoteAddress = null; + + if (localLocation != null) { + localAddress = new InetSocketAddress(InetAddress.getByName(localLocation.getHost()), + localLocation.getPort()); + } + + if (remoteLocation != null) { + String host = resolveHostName(remoteLocation.getHost()); + remoteAddress = new InetSocketAddress(host, remoteLocation.getPort()); + } + // Set the traffic class before the socket is connected when possible so + // that the connection packets are given the correct traffic class. + this.trafficClassSet = setTrafficClass(socket); + + if (socket != null) { + + if (localAddress != null) { + socket.bind(localAddress); + } + + // If it's a server accepted socket.. we don't need to connect it + // to a remote address. + if (remoteAddress != null) { + if (connectionTimeout >= 0) { + socket.connect(remoteAddress, connectionTimeout); + } else { + socket.connect(remoteAddress); + } + } + + } else { + // For SSL sockets.. you can't create an unconnected socket :( + // This means the timout option are not supported either. + if (localAddress != null) { + socket = socketFactory.createSocket(remoteAddress.getAddress(), remoteAddress.getPort(), + localAddress.getAddress(), localAddress.getPort()); + } else { + socket = socketFactory.createSocket(remoteAddress.getAddress(), remoteAddress.getPort()); + } + } + + initialiseSocket(socket); + initializeStreams(); + } + + @Override + protected void doStop(ServiceStopper stopper) throws Exception { + if (LOG.isDebugEnabled()) { + LOG.debug("Stopping transport " + this); + } + + // Closing the streams flush the sockets before closing.. if the socket + // is hung.. then this hangs the close. + // closeStreams(); + if (socket != null) { + if (closeAsync) { + //closing the socket can hang also + final CountDownLatch latch = new CountDownLatch(1); + + // need a async task for this + final TaskRunnerFactory taskRunnerFactory = new TaskRunnerFactory(); + taskRunnerFactory.execute(new Runnable() { + @Override + public void run() { + LOG.trace("Closing socket {}", socket); + try { + socket.close(); + LOG.debug("Closed socket {}", socket); + } catch (IOException e) { + if (LOG.isDebugEnabled()) { + LOG.debug("Caught exception closing socket " + socket + ". This exception will be ignored.", e); + } + } finally { + latch.countDown(); + } + } + }); + + try { + latch.await(1,TimeUnit.SECONDS); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } finally { + taskRunnerFactory.shutdownNow(); + } + + } else { + // close synchronously + LOG.trace("Closing socket {}", socket); + try { + socket.close(); + LOG.debug("Closed socket {}", socket); + } catch (IOException e) { + if (LOG.isDebugEnabled()) { + LOG.debug("Caught exception closing socket " + socket + ". This exception will be ignored.", e); + } + } + } + } + } + + /** + * Override so that stop() blocks until the run thread is no longer running. + */ + @Override + public void stop() throws Exception { + super.stop(); + CountDownLatch countDownLatch = stoppedLatch.get(); + if (countDownLatch != null && Thread.currentThread() != this.runnerThread) { + countDownLatch.await(1,TimeUnit.SECONDS); + } + } + + protected void initializeStreams() throws Exception { + TcpBufferedInputStream buffIn = new TcpBufferedInputStream(socket.getInputStream(), ioBufferSize) { + @Override + public int read() throws IOException { + receiveCounter++; + return super.read(); + } + @Override + public int read(byte[] b, int off, int len) throws IOException { + receiveCounter++; + return super.read(b, off, len); + } + @Override + public long skip(long n) throws IOException { + receiveCounter++; + return super.skip(n); + } + @Override + protected void fill() throws IOException { + receiveCounter++; + super.fill(); + } + }; + //Unread the initBuffer that was used for protocol detection if it exists + //so the stream can start over + if (initBuffer != null) { + buffIn.unread(initBuffer.buffer.array()); + } + this.dataIn = new DataInputStream(buffIn); + TcpBufferedOutputStream outputStream = new TcpBufferedOutputStream(socket.getOutputStream(), ioBufferSize); + this.dataOut = new DataOutputStream(outputStream); + this.buffOut = outputStream; + + } + + protected void closeStreams() throws IOException { + if (dataOut != null) { + dataOut.close(); + } + if (dataIn != null) { + dataIn.close(); + } + } + + public void setSocketOptions(Map socketOptions) { + this.socketOptions = new HashMap(socketOptions); + } + + @Override + public String getRemoteAddress() { + if (socket != null) { + SocketAddress address = socket.getRemoteSocketAddress(); + if (address instanceof InetSocketAddress) { + return "tcp://" + ((InetSocketAddress)address).getAddress().getHostAddress() + ":" + ((InetSocketAddress)address).getPort(); + } else { + return "" + socket.getRemoteSocketAddress(); + } + } + return null; + } + + @Override + public T narrow(Class target) { + if (target == Socket.class) { + return target.cast(socket); + } else if ( target == TimeStampStream.class) { + return target.cast(buffOut); + } + return super.narrow(target); + } + + @Override + public int getReceiveCounter() { + return receiveCounter; + } + + public static class InitBuffer { + public final int readSize; + public final ByteBuffer buffer; + + public InitBuffer(int readSize, ByteBuffer buffer) { + if (buffer == null) { + throw new IllegalArgumentException("Null buffer not allowed."); + } + this.readSize = readSize; + this.buffer = buffer; + } + } + + /** + * @param sock The socket on which to set the Traffic Class. + * @return Whether or not the Traffic Class was set on the given socket. + * @throws SocketException if the system does not support setting the + * Traffic Class. + * @throws IllegalArgumentException if both the Differentiated Services and + * Type of Services transport options have been set on the same + * connection. + */ + private boolean setTrafficClass(Socket sock) throws SocketException, + IllegalArgumentException { + if (sock == null + || (!this.diffServChosen && !this.typeOfServiceChosen)) { + return false; + } + if (this.diffServChosen && this.typeOfServiceChosen) { + throw new IllegalArgumentException("Cannot set both the " + + " Differentiated Services and Type of Services transport " + + " options on the same connection."); + } + + sock.setTrafficClass(this.trafficClass); + + int resultTrafficClass = sock.getTrafficClass(); + if (this.trafficClass != resultTrafficClass) { + // In the case where the user has specified the ECN bits (e.g. in + // Type of Service) but the system won't allow the ECN bits to be + // set or in the case where setting the traffic class failed for + // other reasons, emit a warning. + if ((this.trafficClass >> 2) == (resultTrafficClass >> 2) + && (this.trafficClass & 3) != (resultTrafficClass & 3)) { + LOG.warn("Attempted to set the Traffic Class to " + + this.trafficClass + " but the result Traffic Class was " + + resultTrafficClass + ". Please check that your system " + + "allows you to set the ECN bits (the first two bits)."); + } else { + LOG.warn("Attempted to set the Traffic Class to " + + this.trafficClass + " but the result Traffic Class was " + + resultTrafficClass + ". Please check that your system " + + "supports java.net.setTrafficClass."); + } + return false; + } + // Reset the guards that prevent both the Differentiated Services + // option and the Type of Service option from being set on the same + // connection. + this.diffServChosen = false; + this.typeOfServiceChosen = false; + return true; + } + + @Override + public WireFormat getWireFormat() { + return wireFormat; + } + + @Override + public X509Certificate[] getPeerCertificates() { + return null; + } + + @Override + public void setPeerCertificates(X509Certificate[] certificates) { + } +} \ No newline at end of file diff --git a/src/main/java/org/mule/extensions/jms/internal/connection/provider/activemq/ActiveMQConnectionProvider.java b/src/main/java/org/mule/extensions/jms/internal/connection/provider/activemq/ActiveMQConnectionProvider.java index 462f9287..bbd94594 100644 --- a/src/main/java/org/mule/extensions/jms/internal/connection/provider/activemq/ActiveMQConnectionProvider.java +++ b/src/main/java/org/mule/extensions/jms/internal/connection/provider/activemq/ActiveMQConnectionProvider.java @@ -22,6 +22,7 @@ import org.mule.extensions.jms.internal.ExcludeFromGeneratedCoverage; import org.mule.extensions.jms.internal.connection.exception.ActiveMQException; import org.mule.extensions.jms.internal.connection.provider.BaseConnectionProvider; +import org.mule.extensions.jms.internal.connection.provider.loader.FirewallLoader; import org.mule.jms.commons.internal.connection.JmsConnection; import org.mule.jms.commons.internal.connection.JmsTransactionalConnection; import org.mule.runtime.api.connection.ConnectionException; @@ -46,6 +47,8 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Proxy; +import java.net.URL; +import java.net.URLClassLoader; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.util.function.Supplier; @@ -268,6 +271,12 @@ protected void configureSSLContext() { try { if (tlsConfiguration != null) { SSLContext sslContext = tlsConfiguration.createSslContext(); + ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader(); + // force loading of class from connector instead of the one from the library, because it uses reflection + ClassLoader firewallLoader = new FirewallLoader(currentClassLoader); + ClassLoader loader = new URLClassLoader(new URL[]{this.getClass().getProtectionDomain().getCodeSource().getLocation()}, firewallLoader); + Thread.currentThread().setContextClassLoader(loader); + SslContext activeMQSslContext = new SslContext(); activeMQSslContext.setSSLContext(sslContext); SslContext.setCurrentSslContext(activeMQSslContext); diff --git a/src/main/java/org/mule/extensions/jms/internal/connection/provider/loader/FirewallLoader.java b/src/main/java/org/mule/extensions/jms/internal/connection/provider/loader/FirewallLoader.java new file mode 100644 index 00000000..254ec108 --- /dev/null +++ b/src/main/java/org/mule/extensions/jms/internal/connection/provider/loader/FirewallLoader.java @@ -0,0 +1,13 @@ +package org.mule.extensions.jms.internal.connection.provider.loader; + +public class FirewallLoader extends ClassLoader { + public FirewallLoader(ClassLoader parent) { + super(parent); + } + public Class loadClass(String name, boolean resolve) throws ClassNotFoundException { + if (name.equals("org.apache.activemq.transport.tcp.SslTransport") || name.equals("org.apache.activemq.transport.tcp.TcpTransport")) { + throw new ClassNotFoundException(); + } + return super.loadClass(name, resolve); + } +} \ No newline at end of file diff --git a/src/test/docker/tls/Dockerfile b/src/test/docker/tls/Dockerfile index f0cd97a5..52cce4c8 100644 --- a/src/test/docker/tls/Dockerfile +++ b/src/test/docker/tls/Dockerfile @@ -1,12 +1,20 @@ FROM openjdk:8-jre +RUN wget https://downloads.bouncycastle.org/fips-java/bc-fips-1.0.2.4.jar -P $JAVA_HOME/lib/ext +RUN cp -a $JAVA_HOME/lib/security/java.security $JAVA_HOME/lib/security/java.security.orig +COPY java.security.fips $JAVA_HOME/lib/security/java.security + +RUN cp -a $JAVA_HOME/lib/security/cacerts $JAVA_HOME/lib/security/cacerts.orig +RUN rm $JAVA_HOME/lib/security/cacerts +RUN keytool -importkeystore -srckeystore $JAVA_HOME/lib/security/cacerts.orig -srcstoretype JKS -destkeystore $JAVA_HOME/lib/security/cacerts -deststoretype BCFKS -deststorepass changeit -srcstorepass changeit + ENV ACTIVEMQ_VERSION 5.15.9 ENV ACTIVEMQ apache-activemq-$ACTIVEMQ_VERSION ENV FILENAME $ACTIVEMQ-bin.tar.gz ENV ACTIVEMQ_TCP=61616 ACTIVEMQ_AMQP=5672 ACTIVEMQ_STOMP=61613 ACTIVEMQ_MQTT=1883 ACTIVEMQ_WS=61614 ACTIVEMQ_UI=8161 ENV SHA512_VAL=35cae4258e38e47f9f81e785f547afc457fc331d2177bfc2391277ce24123be1196f10c670b61e30b43b7ab0db0628f3ff33f08660f235b7796d59ba922d444f ENV ACTIVEMQ_HOME /opt/activemq -ENV ACTIVEMQ_SSL_OPTS=-Djavax.net.ssl.keyStore=/opt/activemq/certs/ActiveMq/broker.ks -Djavax.net.ssl.keyStorePassword=racing +ENV ACTIVEMQ_SSL_OPTS=-Djavax.net.ssl.keyStore=/opt/activemq/certs/ActiveMq/broker.ks -Djavax.net.ssl.keyStorePassword=password COPY $FILENAME $FILENAME diff --git a/src/test/docker/tls/activemq.xml b/src/test/docker/tls/activemq.xml index 5eb3bdfa..674f18cc 100644 --- a/src/test/docker/tls/activemq.xml +++ b/src/test/docker/tls/activemq.xml @@ -123,8 +123,10 @@ - + diff --git a/src/test/docker/tls/broker-keystore.ks b/src/test/docker/tls/broker-keystore.ks index 0628356d1d8babac4656b3a8fb518302ae28b91b..a269340a38157d86611c0435408a2d176da472b1 100644 GIT binary patch literal 3742 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 I5|a8re{a?|r2qf` literal 1993 zcmc(gXEYpY8po$AqYc5Z#wepj8#B6K)zMe32`*zvM2sMaPNIx5NKuj~AxiXUlZ`Iq z>X#%WA$s&aMsBcULRNO}-Q9Ec?8*22@c;1pJzw7QoacGoGsYPM004m40sawaV6?wa zG@D|a7&JP&Qi`R3im-ezZex0^9L(98x=~GO(gv^Uaim~bL{74?5_@?A7x2eQ7q}%u*K~fPqyd)n+ zMbF9E3z(W{cuWR2K7PPIZ#iB!jW`|E$wM|TlsHx8l=UC|8u1MgNF{6$wc~m!pU3s2 z`d+3kZRkz-(4y$HN}~bMW0K5{c6_6QiBYni(q{8K2_7UVV9_7>*u`DxLe2h2QO?jw-sNf!l6v z9N>J$!rkI92WNZJvrC*)LXP6Rg9k`}@&aE=$Q&Q$xM1H3>6(qcY|<&h1i#I(4azC5 zd2{>3%;m^yiCl;oc_U%ie=fd8_rOxQs$iK9GPIrZvq}cmQ7xg6uUd#?3 z7=A6+;F%vW)w>;>s%s{gF;#fni*``fh}Qa?Jc6Mleax4CpE%o}?su?Yx3*Y}hsnv? z)GP%EO-1-RYeOL`WW~^M`ZOjeW>QD(${4A{xMCsF*g}*+`9_F=g5h#I-#puWn4@UBo8s8Q^jL!40kg?qRxjbnjBB{I{Vv+(U2eZ zW)~E;UxYbW!-F@Hs>L>kCsbH2*XWjY9QD)w57$z9YL$MgqV^9MYsrLY;9C~x%8v7O5_5O3U2;~@G3$$;-?efj$*;FO1P)|?qr}+2>@J$G z^}oi}RZR=42LM3UuoTD=JL#oh5D)}{*rd2*V0mF&Ua3|V{oCa1Kr>mi>iNoUE z{y;sP_P_D}@gxe^l)c(oFpl%7R%5ylAR81x6d(|g8Lc(j@oeW+9V0Df-1=hcq1s@v zL6Z)0dv_ogZS)Uq*p}JF+5se9ubpeFuTjFOu$thW@($6^-W*L0w@&sW)$?VZd!fy# z_*DHw0l{r}rS^e^CRgd1Ux1}6%l4C0Vv!D4sesG#M-6WQvWA_+~zPP_0Q^LuKb(AdcwPg{&y^$ zhVT}d2?n@|zU70PS#mcVj57>4b;|}E*H`X}E0y0~`fHilqV2WskSwE*<07&vu9MUu z&YgH^i5b+W?CTr496l_WHPap|J7|QSo|nXwF9-$bWad_-L>(_JZk_m!L=LBX#{CW7 zxsmY8%a48@>>dF`sz|OYk}1YCHe_^B_2l{vFw2n|N`W=hJxPKUEAG^D zv5lCl;V*+*+;IBT1VSkDqCs=mJRIgsp>gic6I&&j+0Hv_#j`8mstZ3Q!iUn@RvBg@ zE1yN@7r_+vC-8eCd~HIvP&j#XKd%qJL369VyQ@zE?8$JCX98cXniJK4kiZ?uYt%{j z^hU>})G9bv>s<3`+l}ox$!@18q65O(SiaAlveFr!jr(w_Z)T7)>lKvks6rPC5gy4f zIS`E%^ti}MatmHntj1@BpI>e;{$?xk_ z>Duj*ij5T{g96hw_l9Z~PZ=r~z&UNWmd<;9DgkNe($P}9eiZm!OUk;YFfixUD`j(@ zj~2>D`rhTzSTq*JJ|8GPhzR5ypYFAOhWC(6?Ec_&!No7z8(P*n|8sr7CIGAvd&H9Q zvZ1}l^{_o2N>{zTse#Q~YO6!ThQ#Sfk}|vec%%bWqg&#KtCb+4i(U9hbBAjjyXk3{ coz!XF}f_wIS2V z($gkdo_6U2I|2eg00IFZFboC=Duzgg_YDFI1pqJ}1_@w>NC9O71OYEF5d;isYu{?h z35zir#V?zxfV<;=T@xQ_66o$+GR$It`fnFi8C7hq(_*=oEGj#sam18?-GZPz9Wx9@I zmq~~5DY*L~S0dalm<#xX#_J>>xa2=xAWP|RhBze?+ z_EUt}xN*6&_vlQhB8C!`4&5-AGA>9MO{4um>IcH$-9GzWoOuY0>=S(zBP@)Y3!jQS z5L;R(0klHA8h3NvZRLD0NB$%yz&vw8vmDT8kLDZ&*;!i8{p(r&s|V>b&G6Llvy+e< zo_D}+EsTkfE8~}$U=H*``>d{brjJc3NW-^s7t&vdM;F)aPBG_xvor`YAY4)zPz>TK z7hz`+uj&T%5{(6fBaFdjnK3o$QxTUMHi2(UQpX{MjM&dj~N_5V+%~9pzo>H z#zuh1ddwcm3UIm?D9{xJ;hfIw5m6lv0+i~E3wcaiU~FYli|FQ8+Q#6K9^sf+-EfBL zv(=_&97$&0fnvk_JC^V~rhYuPk?-p`na|%XHsBfUC=lBuLx8mx?655$(0Y#|6E#iOGO|H6eKiy=orNbG@cgldjG3l;m^%ZN3CNqi zySnKhfu>0@+qq{2qP~s8e?iY29~O?>Ph)qWUvW<{`m0IZ?)2-Hv?tk~P&M{#>sJt@ za!~2eJ^T$r^#@V`NFoy7Psf)Sq)F5AUR^GMuY`LY`Eah`3li08Uzl}Vj_bmj^KAv* z?LpmR(+K!drIiH!R(=Apl{5KwzV+?ZDwj;TicLy(i&43T#wBJGv{Zc%w5r!rPN(xW zo>g4x-t9dXI4j%`9X3i%C2*@GrN5(}Z|RtMJv;MZU{fLGe37{JC}H>*@NCaIF5gnT zt_G1pu0;ispHj54b!@NQVU?#-Jv~}@%UDoqyeE7xWS*l{)&Ec#;&D7bI&rg2>?jd} zp0lSFzUh>bIa~0ND#pq<+bq3+NcqqKjO=KtD{V&EZXjFX^At&Ko39ivR}H^r*vl24 zDfC~tsPS6h=}u`wCVun(iH*O-pOQMCwN5GoXS2E$B#YWhk%TLyx>$~o0k^{=0HU7C zKM08i*4Fmjs(PG7=tl;e#cTf6JYhA$J1sMUiQZXZ4Bv)n5#0i=jsRPN0P%<;^@O(y zBHbs*++h?w+_%o<(n3y(*cV}N8Rv)SaJ$v-j4)c~ z^)#kjF<@ZYKy{?3i2ptV%URA5a5$S4J$ltzGvi;|NEBcwF)#P8Llhl&u{?O4o#(2v zhId5L2N-s=d}SBi$PNe5PLa249%f|D?$qxw5qzJ_9rCCsB^@@BzcO;x|e7Qm^`bef{?8zxfBeqCrNp##UP!5tVRzJ{!V+l<> z**a)})a|yu{b~c{eE|kbVtsh_A4kL9cprPeJ-D38w|qK&ybg``v(?)Fto$(Yy%W7& zVG3`0g;m@a6a2dFWeL5IlEzSgQCIAQ#V z9FEp}Y~0c1s;2!z{2)PXPENcsO6>rV{MakgRBt;0n`4InFK(nl3yqN4g7q>k=Wj>q zv-M(6u1$}^&HGfGf7bkYwZ8Cyg(2pO;slK0f9*2=iks<|4M$OFeF_F$N{hTpxYg7= zs2(rLwE?+(YFr`u<;ar>=wZgN)pb}BZ=u6_biId054Ijr!$BhZ0APo{T2Ux&B z*ojT{V05l&Z+h6m?qO3)m>+OrC%y%F)I1aTiuz=y!!|cQb)b@{jKllx?z3-tBL7%Y z0&dlD;XhcmFd9}z7@yeX}`aS#AME^Xs-4$h&lIr-qC&>Orn zzIfi6XV}AvFLDR`6s%phgNc$YLyC3EK>DZb*CNgpDRBvP!4T3$ispHrmILbXzs_SQ z&m79#o=X-&8wi25Q6N1&U!+_^P@#U+W^q|(En@|&W^o;M6%}+^k@qDmf3kq@z8xmF zQseC-!=&s!*9XX&{8S{A8kpfXI-VmMmMUx};l$AGmq30>*5DMK8S>KI5=Po_`~z5~ z$%sETUwtqp_5as!a%!ZbvUu5Uz4!uNcRlDS|56>aNAIcgRgeT|VElCY$&W&;N3<#b zwf5cCu=&O8GT!A;@1+U+C&vMjD<{^|v-7n#^Rdzh zyYMW|)%hgGp*MU_Oc^PsYII*EEfINJ{l(4-9uRG^x4}$+(zcz2=*8yCaLiNoHF!as zpY4}X=!#;w>*j!ROJzFVsvZJ4lm&k+rdl#l7p)0Tb{~Yxyq--y z)ag3C%11gU&yUD5B7(%=%4yZN4)XYTS-O4eT=Im)hStD3zmA=(co~cDX?#MFE?%S| zz=@|%Yb1=PbMcf)4ueh%c2jYw|Jx<^n$MJN6m=KlTUC~bCd3vUx8Oq| zZ1IAOLAa101EmI&!`87(nE}Cz=wRkzs&&{}IUu;vfFuL|#&pJGQjH5N6yxPLA@*Lvhj4+);k1;AHLv@Z z zel5k_>2 zen08(*L`Td#HT&h(u^_ucO5RgtO^zCnRdZw`5_$?wH=mDBHajS&P)U8;c73!-ss2X znYSHbDO)dC2lIJ=$dNXmLG#Mot%LIcGMEdsuSa}F1>d1Ei3yJ;w6c0RpSBy8_1Tdg z2wGgJG4%_DRCd&iw7S{hLiXg02cp2d1P^QLVo2BP6loN={XgMl*I7YNu2`C2ZV z2xIIohZq6jw_Fv*3DgP5BcJSAsavm#OaF6Pe6g>K4XeWhYNL|r&l5yMkx0z5x7%#2 zxdT~?PQ!4D_`w~LF}DU48RHU7(Mkc<6_+PE*0{ycH3uR$aP<5&L zNQU&R|G)O;Q(Q*L0r`%Z{E9Xa!Hy}xiHH9hXbNwEVs^$V3+?#m>cRUgMDL4K5TCyxZsU596bb98SEqVl JChN)Jc;o*}B0B&8 literal 1313 zcmezO_TO6u1_mY|W(3o$xs}lb@WJlaXIs z0uy7$BF2S9j2nv>Gm@BroH(zMp@Er^g`tIsk%4g(m}_Zd2IUTflbV>F44Rls+1Rz( zJkD9LFakLmOihf84E>d+H+QajxqtQBj;iyXf!jXo9i3;r-dy6vt0U9o?f#mvJ$DXV zc|^k4atG)0L+fOMXD@e;ZoMG5cE^^=_EOK5%$PNN{UV#qI5ZaN|56v^vQ1h!+0}$| z!N1HLw}>C!cNH4vm~$==2;Vq$?O6t8+g%|o+cf3pru6-2c4;f0KIaX~7L#Rb^h#gO zh<#+cK~w*rV9)$ta~m6<8~1LXwB6wP&c~jS`Wc)vibO3%U)g4Ny9FOJcI|JlHd=D% z!Kb1Ls(F6)UDg~H3y%amdDtVRxw!Uz+(PGj-f90?CfHp)FQ)u3;!685j+ga{GB;#T zDWA@>U{C#_^w?>ihYxF+rDcN5wR9#~hF#yLEo-g#e*fO{U+E{ykGH-z+GM=zX~Tg% zS2JUQVZv-g&_8}w@?yj(Kv^3vGg=+}Q-uY8mIW^em;ce|zPp-(Cg$_+JhSG2#8 zbNBdB_dEXH_K+6CY$c<6PlNBSXA;!rm1nwTFx^PypZdC6-E+M)m2U3pemw8yL*`{R zL5n!&0z4+~W%uS4}44{BW_bPraYosQBm^YQ*ddoJe=!nz?wztJ&|9eX*orcG9Uit;V`ilcXj{K4g`bl6v;- zhvv?i@h11&SB6weI_7^iYGcf}xLWtM*$z34bxUHbXF6??>OA9wO* zU2BlA4d1zS-jgr6|4kJfv>McU!F z$;Xtc-yO{oy7%$LQ&UfKw9<#!k-@+Yn8aF)m5UF4U&Ho>r)l>ZUngs?v+djb);^W_ z{i|6UC_U@sPT3U}^D~WB%7n_IQ`3OulY3V|3;;E J53vL#000c71^xg4 diff --git a/src/test/docker/tls/java.security.fips b/src/test/docker/tls/java.security.fips new file mode 100644 index 00000000..69cc4239 --- /dev/null +++ b/src/test/docker/tls/java.security.fips @@ -0,0 +1,955 @@ +#BC fips + +# +# List of providers and their preference orders (see above): +# + +security.provider.1=org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider +security.provider.2=com.sun.net.ssl.internal.ssl.Provider BCFIPS +security.provider.3=sun.security.provider.Sun + +security.provider.4=sun.security.rsa.SunRsaSign +security.provider.5=sun.security.ec.SunEC +security.provider.6=com.sun.crypto.provider.SunJCE +security.provider.7=sun.security.jgss.SunProvider +security.provider.8=com.sun.security.sasl.Provider +security.provider.9=org.jcp.xml.dsig.internal.dom.XMLDSigRI +security.provider.10=sun.security.smartcardio.SunPCSC + +# +# Sun Provider SecureRandom seed source. +# +# Select the primary source of seed data for the "SHA1PRNG" and +# "NativePRNG" SecureRandom implementations in the "Sun" provider. +# (Other SecureRandom implementations might also use this property.) +# +# On Unix-like systems (for example, Solaris/Linux/MacOS), the +# "NativePRNG" and "SHA1PRNG" implementations obtains seed data from +# special device files such as file:/dev/random. +# +# On Windows systems, specifying the URLs "file:/dev/random" or +# "file:/dev/urandom" will enable the native Microsoft CryptoAPI seeding +# mechanism for SHA1PRNG. +# +# By default, an attempt is made to use the entropy gathering device +# specified by the "securerandom.source" Security property. If an +# exception occurs while accessing the specified URL: +# +# SHA1PRNG: +# the traditional system/thread activity algorithm will be used. +# +# NativePRNG: +# a default value of /dev/random will be used. If neither +# are available, the implementation will be disabled. +# "file" is the only currently supported protocol type. +# +# The entropy gathering device can also be specified with the System +# property "java.security.egd". For example: +# +# % java -Djava.security.egd=file:/dev/random MainClass +# +# Specifying this System property will override the +# "securerandom.source" Security property. +# +# In addition, if "file:/dev/random" or "file:/dev/urandom" is +# specified, the "NativePRNG" implementation will be more preferred than +# SHA1PRNG in the Sun provider. +# +securerandom.source=file:/dev/random + +# +# A list of known strong SecureRandom implementations. +# +# To help guide applications in selecting a suitable strong +# java.security.SecureRandom implementation, Java distributions should +# indicate a list of known strong implementations using the property. +# +# This is a comma-separated list of algorithm and/or algorithm:provider +# entries. +# +securerandom.strongAlgorithms=NativePRNGBlocking:SUN + +# +# Class to instantiate as the javax.security.auth.login.Configuration +# provider. +# +login.configuration.provider=sun.security.provider.ConfigFile + +# +# Default login configuration file +# +#login.config.url.1=file:${user.home}/.java.login.config + +# +# Class to instantiate as the system Policy. This is the name of the class +# that will be used as the Policy object. +# +policy.provider=sun.security.provider.PolicyFile + +# The default is to have a single system-wide policy file, +# and a policy file in the user's home directory. +policy.url.1=file:${java.home}/lib/security/java.policy +policy.url.2=file:${user.home}/.java.policy + +# whether or not we expand properties in the policy file +# if this is set to false, properties (${...}) will not be expanded in policy +# files. +policy.expandProperties=true + +# whether or not we allow an extra policy to be passed on the command line +# with -Djava.security.policy=somefile. Comment out this line to disable +# this feature. +policy.allowSystemProperty=true + +# whether or not we look into the IdentityScope for trusted Identities +# when encountering a 1.1 signed JAR file. If the identity is found +# and is trusted, we grant it AllPermission. +policy.ignoreIdentityScope=false + +# +# Default keystore type. +# +keystore.type=BCFKS + +# +# Controls compatibility mode for the JKS keystore type. +# +# When set to 'true', the JKS keystore type supports loading +# keystore files in either JKS or PKCS12 format. When set to 'false' +# it supports loading only JKS keystore files. +# +keystore.type.compat=false + +# +# List of comma-separated packages that start with or equal this string +# will cause a security exception to be thrown when +# passed to checkPackageAccess unless the +# corresponding RuntimePermission ("accessClassInPackage."+package) has +# been granted. +package.access=sun.,\ + org.GNOME.Accessibility.,\ + com.sun.xml.internal.,\ + com.sun.imageio.,\ + com.sun.istack.internal.,\ + com.sun.jmx.,\ + com.sun.media.sound.,\ + com.sun.naming.internal.,\ + com.sun.proxy.,\ + com.sun.corba.se.,\ + com.sun.org.apache.bcel.internal.,\ + com.sun.org.apache.regexp.internal.,\ + com.sun.org.apache.xerces.internal.,\ + com.sun.org.apache.xpath.internal.,\ + com.sun.org.apache.xalan.internal.extensions.,\ + com.sun.org.apache.xalan.internal.lib.,\ + com.sun.org.apache.xalan.internal.res.,\ + com.sun.org.apache.xalan.internal.templates.,\ + com.sun.org.apache.xalan.internal.utils.,\ + com.sun.org.apache.xalan.internal.xslt.,\ + com.sun.org.apache.xalan.internal.xsltc.cmdline.,\ + com.sun.org.apache.xalan.internal.xsltc.compiler.,\ + com.sun.org.apache.xalan.internal.xsltc.trax.,\ + com.sun.org.apache.xalan.internal.xsltc.util.,\ + com.sun.org.apache.xml.internal.res.,\ + com.sun.org.apache.xml.internal.resolver.helpers.,\ + com.sun.org.apache.xml.internal.resolver.readers.,\ + com.sun.org.apache.xml.internal.security.,\ + com.sun.org.apache.xml.internal.serializer.utils.,\ + com.sun.org.apache.xml.internal.utils.,\ + com.sun.org.glassfish.,\ + com.oracle.xmlns.internal.,\ + com.oracle.webservices.internal.,\ + oracle.jrockit.jfr.,\ + org.jcp.xml.dsig.internal.,\ + jdk.internal.,\ + jdk.nashorn.internal.,\ + jdk.nashorn.tools.,\ + jdk.xml.internal.,\ + com.sun.activation.registries. + +# +# List of comma-separated packages that start with or equal this string +# will cause a security exception to be thrown when +# passed to checkPackageDefinition unless the +# corresponding RuntimePermission ("defineClassInPackage."+package) has +# been granted. +# +# by default, none of the class loaders supplied with the JDK call +# checkPackageDefinition. +# +package.definition=sun.,\ + com.sun.xml.internal.,\ + com.sun.imageio.,\ + com.sun.istack.internal.,\ + com.sun.jmx.,\ + com.sun.media.sound.,\ + com.sun.naming.internal.,\ + com.sun.proxy.,\ + com.sun.corba.se.,\ + com.sun.org.apache.bcel.internal.,\ + com.sun.org.apache.regexp.internal.,\ + com.sun.org.apache.xerces.internal.,\ + com.sun.org.apache.xpath.internal.,\ + com.sun.org.apache.xalan.internal.extensions.,\ + com.sun.org.apache.xalan.internal.lib.,\ + com.sun.org.apache.xalan.internal.res.,\ + com.sun.org.apache.xalan.internal.templates.,\ + com.sun.org.apache.xalan.internal.utils.,\ + com.sun.org.apache.xalan.internal.xslt.,\ + com.sun.org.apache.xalan.internal.xsltc.cmdline.,\ + com.sun.org.apache.xalan.internal.xsltc.compiler.,\ + com.sun.org.apache.xalan.internal.xsltc.trax.,\ + com.sun.org.apache.xalan.internal.xsltc.util.,\ + com.sun.org.apache.xml.internal.res.,\ + com.sun.org.apache.xml.internal.resolver.helpers.,\ + com.sun.org.apache.xml.internal.resolver.readers.,\ + com.sun.org.apache.xml.internal.security.,\ + com.sun.org.apache.xml.internal.serializer.utils.,\ + com.sun.org.apache.xml.internal.utils.,\ + com.sun.org.glassfish.,\ + com.oracle.xmlns.internal.,\ + com.oracle.webservices.internal.,\ + oracle.jrockit.jfr.,\ + org.jcp.xml.dsig.internal.,\ + jdk.internal.,\ + jdk.nashorn.internal.,\ + jdk.nashorn.tools.,\ + jdk.xml.internal.,\ + com.sun.activation.registries. + +# +# Determines whether this properties file can be appended to +# or overridden on the command line via -Djava.security.properties +# +security.overridePropertiesFile=true + +# +# Determines the default key and trust manager factory algorithms for +# the javax.net.ssl package. +# +ssl.KeyManagerFactory.algorithm=SunX509 +ssl.TrustManagerFactory.algorithm=PKIX + +# +# The Java-level namelookup cache policy for successful lookups: +# +# any negative value: caching forever +# any positive value: the number of seconds to cache an address for +# zero: do not cache +# +# default value is forever (FOREVER). For security reasons, this +# caching is made forever when a security manager is set. When a security +# manager is not set, the default behavior in this implementation +# is to cache for 30 seconds. +# +# NOTE: setting this to anything other than the default value can have +# serious security implications. Do not set it unless +# you are sure you are not exposed to DNS spoofing attack. +# +#networkaddress.cache.ttl=-1 + +# The Java-level namelookup cache policy for failed lookups: +# +# any negative value: cache forever +# any positive value: the number of seconds to cache negative lookup results +# zero: do not cache +# +# In some Microsoft Windows networking environments that employ +# the WINS name service in addition to DNS, name service lookups +# that fail may take a noticeably long time to return (approx. 5 seconds). +# For this reason the default caching policy is to maintain these +# results for 10 seconds. +# +# +networkaddress.cache.negative.ttl=10 + +# +# Properties to configure OCSP for certificate revocation checking +# + +# Enable OCSP +# +# By default, OCSP is not used for certificate revocation checking. +# This property enables the use of OCSP when set to the value "true". +# +# NOTE: SocketPermission is required to connect to an OCSP responder. +# +# Example, +# ocsp.enable=true + +# +# Location of the OCSP responder +# +# By default, the location of the OCSP responder is determined implicitly +# from the certificate being validated. This property explicitly specifies +# the location of the OCSP responder. The property is used when the +# Authority Information Access extension (defined in RFC 3280) is absent +# from the certificate or when it requires overriding. +# +# Example, +# ocsp.responderURL=http://ocsp.example.net:80 + +# +# Subject name of the OCSP responder's certificate +# +# By default, the certificate of the OCSP responder is that of the issuer +# of the certificate being validated. This property identifies the certificate +# of the OCSP responder when the default does not apply. Its value is a string +# distinguished name (defined in RFC 2253) which identifies a certificate in +# the set of certificates supplied during cert path validation. In cases where +# the subject name alone is not sufficient to uniquely identify the certificate +# then both the "ocsp.responderCertIssuerName" and +# "ocsp.responderCertSerialNumber" properties must be used instead. When this +# property is set then those two properties are ignored. +# +# Example, +# ocsp.responderCertSubjectName="CN=OCSP Responder, O=XYZ Corp" + +# +# Issuer name of the OCSP responder's certificate +# +# By default, the certificate of the OCSP responder is that of the issuer +# of the certificate being validated. This property identifies the certificate +# of the OCSP responder when the default does not apply. Its value is a string +# distinguished name (defined in RFC 2253) which identifies a certificate in +# the set of certificates supplied during cert path validation. When this +# property is set then the "ocsp.responderCertSerialNumber" property must also +# be set. When the "ocsp.responderCertSubjectName" property is set then this +# property is ignored. +# +# Example, +# ocsp.responderCertIssuerName="CN=Enterprise CA, O=XYZ Corp" + +# +# Serial number of the OCSP responder's certificate +# +# By default, the certificate of the OCSP responder is that of the issuer +# of the certificate being validated. This property identifies the certificate +# of the OCSP responder when the default does not apply. Its value is a string +# of hexadecimal digits (colon or space separators may be present) which +# identifies a certificate in the set of certificates supplied during cert path +# validation. When this property is set then the "ocsp.responderCertIssuerName" +# property must also be set. When the "ocsp.responderCertSubjectName" property +# is set then this property is ignored. +# +# Example, +# ocsp.responderCertSerialNumber=2A:FF:00 + +# +# Policy for failed Kerberos KDC lookups: +# +# When a KDC is unavailable (network error, service failure, etc), it is +# put inside a blacklist and accessed less often for future requests. The +# value (case-insensitive) for this policy can be: +# +# tryLast +# KDCs in the blacklist are always tried after those not on the list. +# +# tryLess[:max_retries,timeout] +# KDCs in the blacklist are still tried by their order in the configuration, +# but with smaller max_retries and timeout values. max_retries and timeout +# are optional numerical parameters (default 1 and 5000, which means once +# and 5 seconds). Please notes that if any of the values defined here is +# more than what is defined in krb5.conf, it will be ignored. +# +# Whenever a KDC is detected as available, it is removed from the blacklist. +# The blacklist is reset when krb5.conf is reloaded. You can add +# refreshKrb5Config=true to a JAAS configuration file so that krb5.conf is +# reloaded whenever a JAAS authentication is attempted. +# +# Example, +# krb5.kdc.bad.policy = tryLast +# krb5.kdc.bad.policy = tryLess:2,2000 +krb5.kdc.bad.policy = tryLast + +# Algorithm restrictions for certification path (CertPath) processing +# +# In some environments, certain algorithms or key lengths may be undesirable +# for certification path building and validation. For example, "MD2" is +# generally no longer considered to be a secure hash algorithm. This section +# describes the mechanism for disabling algorithms based on algorithm name +# and/or key length. This includes algorithms used in certificates, as well +# as revocation information such as CRLs and signed OCSP Responses. +# The syntax of the disabled algorithm string is described as follows: +# DisabledAlgorithms: +# " DisabledAlgorithm { , DisabledAlgorithm } " +# +# DisabledAlgorithm: +# AlgorithmName [Constraint] { '&' Constraint } +# +# AlgorithmName: +# (see below) +# +# Constraint: +# KeySizeConstraint | CAConstraint | DenyAfterConstraint | +# UsageConstraint +# +# KeySizeConstraint: +# keySize Operator KeyLength +# +# Operator: +# <= | < | == | != | >= | > +# +# KeyLength: +# Integer value of the algorithm's key length in bits +# +# CAConstraint: +# jdkCA +# +# DenyAfterConstraint: +# denyAfter YYYY-MM-DD +# +# UsageConstraint: +# usage [TLSServer] [TLSClient] [SignedJAR] +# +# The "AlgorithmName" is the standard algorithm name of the disabled +# algorithm. See "Java Cryptography Architecture Standard Algorithm Name +# Documentation" for information about Standard Algorithm Names. Matching +# is performed using a case-insensitive sub-element matching rule. (For +# example, in "SHA1withECDSA" the sub-elements are "SHA1" for hashing and +# "ECDSA" for signatures.) If the assertion "AlgorithmName" is a +# sub-element of the certificate algorithm name, the algorithm will be +# rejected during certification path building and validation. For example, +# the assertion algorithm name "DSA" will disable all certificate algorithms +# that rely on DSA, such as NONEwithDSA, SHA1withDSA. However, the assertion +# will not disable algorithms related to "ECDSA". +# +# A "Constraint" defines restrictions on the keys and/or certificates for +# a specified AlgorithmName: +# +# KeySizeConstraint: +# keySize Operator KeyLength +# The constraint requires a key of a valid size range if the +# "AlgorithmName" is of a key algorithm. The "KeyLength" indicates +# the key size specified in number of bits. For example, +# "RSA keySize <= 1024" indicates that any RSA key with key size less +# than or equal to 1024 bits should be disabled, and +# "RSA keySize < 1024, RSA keySize > 2048" indicates that any RSA key +# with key size less than 1024 or greater than 2048 should be disabled. +# This constraint is only used on algorithms that have a key size. +# +# CAConstraint: +# jdkCA +# This constraint prohibits the specified algorithm only if the +# algorithm is used in a certificate chain that terminates at a marked +# trust anchor in the lib/security/cacerts keystore. If the jdkCA +# constraint is not set, then all chains using the specified algorithm +# are restricted. jdkCA may only be used once in a DisabledAlgorithm +# expression. +# Example: To apply this constraint to SHA-1 certificates, include +# the following: "SHA1 jdkCA" +# +# DenyAfterConstraint: +# denyAfter YYYY-MM-DD +# This constraint prohibits a certificate with the specified algorithm +# from being used after the date regardless of the certificate's +# validity. JAR files that are signed and timestamped before the +# constraint date with certificates containing the disabled algorithm +# will not be restricted. The date is processed in the UTC timezone. +# This constraint can only be used once in a DisabledAlgorithm +# expression. +# Example: To deny usage of RSA 2048 bit certificates after Feb 3 2020, +# use the following: "RSA keySize == 2048 & denyAfter 2020-02-03" +# +# UsageConstraint: +# usage [TLSServer] [TLSClient] [SignedJAR] +# This constraint prohibits the specified algorithm for +# a specified usage. This should be used when disabling an algorithm +# for all usages is not practical. 'TLSServer' restricts the algorithm +# in TLS server certificate chains when server authentication is +# performed. 'TLSClient' restricts the algorithm in TLS client +# certificate chains when client authentication is performed. +# 'SignedJAR' constrains use of certificates in signed jar files. +# The usage type follows the keyword and more than one usage type can +# be specified with a whitespace delimiter. +# Example: "SHA1 usage TLSServer TLSClient" +# +# When an algorithm must satisfy more than one constraint, it must be +# delimited by an ampersand '&'. For example, to restrict certificates in a +# chain that terminate at a distribution provided trust anchor and contain +# RSA keys that are less than or equal to 1024 bits, add the following +# constraint: "RSA keySize <= 1024 & jdkCA". +# +# All DisabledAlgorithms expressions are processed in the order defined in the +# property. This requires lower keysize constraints to be specified +# before larger keysize constraints of the same algorithm. For example: +# "RSA keySize < 1024 & jdkCA, RSA keySize < 2048". +# +# Note: The algorithm restrictions do not apply to trust anchors or +# self-signed certificates. +# +# Note: This property is currently used by Oracle's PKIX implementation. It +# is not guaranteed to be examined and used by other implementations. +# +# Example: +# jdk.certpath.disabledAlgorithms=MD2, DSA, RSA keySize < 2048 +# +# +jdk.certpath.disabledAlgorithms=MD2, MD5, SHA1 jdkCA & usage TLSServer, \ + RSA keySize < 1024, DSA keySize < 1024, EC keySize < 224 + +# +# Algorithm restrictions for signed JAR files +# +# In some environments, certain algorithms or key lengths may be undesirable +# for signed JAR validation. For example, "MD2" is generally no longer +# considered to be a secure hash algorithm. This section describes the +# mechanism for disabling algorithms based on algorithm name and/or key length. +# JARs signed with any of the disabled algorithms or key sizes will be treated +# as unsigned. +# +# The syntax of the disabled algorithm string is described as follows: +# DisabledAlgorithms: +# " DisabledAlgorithm { , DisabledAlgorithm } " +# +# DisabledAlgorithm: +# AlgorithmName [Constraint] { '&' Constraint } +# +# AlgorithmName: +# (see below) +# +# Constraint: +# KeySizeConstraint | DenyAfterConstraint +# +# KeySizeConstraint: +# keySize Operator KeyLength +# +# DenyAfterConstraint: +# denyAfter YYYY-MM-DD +# +# Operator: +# <= | < | == | != | >= | > +# +# KeyLength: +# Integer value of the algorithm's key length in bits +# +# Note: This property is currently used by the JDK Reference +# implementation. It is not guaranteed to be examined and used by other +# implementations. +# +# See "jdk.certpath.disabledAlgorithms" for syntax descriptions. +# +jdk.jar.disabledAlgorithms=MD2, MD5, RSA keySize < 1024, DSA keySize < 1024 + +# +# Algorithm restrictions for Secure Socket Layer/Transport Layer Security +# (SSL/TLS) processing +# +# In some environments, certain algorithms or key lengths may be undesirable +# when using SSL/TLS. This section describes the mechanism for disabling +# algorithms during SSL/TLS security parameters negotiation, including +# protocol version negotiation, cipher suites selection, peer authentication +# and key exchange mechanisms. +# +# Disabled algorithms will not be negotiated for SSL/TLS connections, even +# if they are enabled explicitly in an application. +# +# For PKI-based peer authentication and key exchange mechanisms, this list +# of disabled algorithms will also be checked during certification path +# building and validation, including algorithms used in certificates, as +# well as revocation information such as CRLs and signed OCSP Responses. +# This is in addition to the jdk.certpath.disabledAlgorithms property above. +# +# See the specification of "jdk.certpath.disabledAlgorithms" for the +# syntax of the disabled algorithm string. +# +# Note: The algorithm restrictions do not apply to trust anchors or +# self-signed certificates. +# +# Note: This property is currently used by the JDK Reference implementation. +# It is not guaranteed to be examined and used by other implementations. +# +# Example: +# jdk.tls.disabledAlgorithms=MD5, SSLv3, DSA, RSA keySize < 2048 +jdk.tls.disabledAlgorithms=SSLv3, RC4, DES, MD5withRSA, DH keySize < 1024, \ + EC keySize < 224, 3DES_EDE_CBC, anon, NULL + +# Legacy algorithms for Secure Socket Layer/Transport Layer Security (SSL/TLS) +# processing in JSSE implementation. +# +# In some environments, a certain algorithm may be undesirable but it +# cannot be disabled because of its use in legacy applications. Legacy +# algorithms may still be supported, but applications should not use them +# as the security strength of legacy algorithms are usually not strong enough +# in practice. +# +# During SSL/TLS security parameters negotiation, legacy algorithms will +# not be negotiated unless there are no other candidates. +# +# The syntax of the legacy algorithms string is described as this Java +# BNF-style: +# LegacyAlgorithms: +# " LegacyAlgorithm { , LegacyAlgorithm } " +# +# LegacyAlgorithm: +# AlgorithmName (standard JSSE algorithm name) +# +# See the specification of security property "jdk.certpath.disabledAlgorithms" +# for the syntax and description of the "AlgorithmName" notation. +# +# Per SSL/TLS specifications, cipher suites have the form: +# SSL_KeyExchangeAlg_WITH_CipherAlg_MacAlg +# or +# TLS_KeyExchangeAlg_WITH_CipherAlg_MacAlg +# +# For example, the cipher suite TLS_RSA_WITH_AES_128_CBC_SHA uses RSA as the +# key exchange algorithm, AES_128_CBC (128 bits AES cipher algorithm in CBC +# mode) as the cipher (encryption) algorithm, and SHA-1 as the message digest +# algorithm for HMAC. +# +# The LegacyAlgorithm can be one of the following standard algorithm names: +# 1. JSSE cipher suite name, e.g., TLS_RSA_WITH_AES_128_CBC_SHA +# 2. JSSE key exchange algorithm name, e.g., RSA +# 3. JSSE cipher (encryption) algorithm name, e.g., AES_128_CBC +# 4. JSSE message digest algorithm name, e.g., SHA +# +# See SSL/TLS specifications and "Java Cryptography Architecture Standard +# Algorithm Name Documentation" for information about the algorithm names. +# +# Note: This property is currently used by the JDK Reference implementation. +# It is not guaranteed to be examined and used by other implementations. +# There is no guarantee the property will continue to exist or be of the +# same syntax in future releases. +# +# Example: +# jdk.tls.legacyAlgorithms=DH_anon, DES_CBC, SSL_RSA_WITH_RC4_128_MD5 +# +jdk.tls.legacyAlgorithms= \ + K_NULL, C_NULL, M_NULL, \ + DH_anon, ECDH_anon, \ + RC4_128, RC4_40, DES_CBC, DES40_CBC, \ + 3DES_EDE_CBC + +# The pre-defined default finite field Diffie-Hellman ephemeral (DHE) +# parameters for Transport Layer Security (SSL/TLS/DTLS) processing. +# +# In traditional SSL/TLS/DTLS connections where finite field DHE parameters +# negotiation mechanism is not used, the server offers the client group +# parameters, base generator g and prime modulus p, for DHE key exchange. +# It is recommended to use dynamic group parameters. This property defines +# a mechanism that allows you to specify custom group parameters. +# +# The syntax of this property string is described as this Java BNF-style: +# DefaultDHEParameters: +# DefinedDHEParameters { , DefinedDHEParameters } +# +# DefinedDHEParameters: +# "{" DHEPrimeModulus , DHEBaseGenerator "}" +# +# DHEPrimeModulus: +# HexadecimalDigits +# +# DHEBaseGenerator: +# HexadecimalDigits +# +# HexadecimalDigits: +# HexadecimalDigit { HexadecimalDigit } +# +# HexadecimalDigit: one of +# 0 1 2 3 4 5 6 7 8 9 A B C D E F a b c d e f +# +# Whitespace characters are ignored. +# +# The "DefinedDHEParameters" defines the custom group parameters, prime +# modulus p and base generator g, for a particular size of prime modulus p. +# The "DHEPrimeModulus" defines the hexadecimal prime modulus p, and the +# "DHEBaseGenerator" defines the hexadecimal base generator g of a group +# parameter. It is recommended to use safe primes for the custom group +# parameters. +# +# If this property is not defined or the value is empty, the underlying JSSE +# provider's default group parameter is used for each connection. +# +# If the property value does not follow the grammar, or a particular group +# parameter is not valid, the connection will fall back and use the +# underlying JSSE provider's default group parameter. +# +# Note: This property is currently used by OpenJDK's JSSE implementation. It +# is not guaranteed to be examined and used by other implementations. +# +# Example: +# jdk.tls.server.defaultDHEParameters= +# { \ +# FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1 \ +# 29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD \ +# EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245 \ +# E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED \ +# EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE65381 \ +# FFFFFFFF FFFFFFFF, 2} + +# Cryptographic Jurisdiction Policy defaults +# +# Import and export control rules on cryptographic software vary from +# country to country. By default, the JDK provides two different sets of +# cryptographic policy files: +# +# unlimited: These policy files contain no restrictions on cryptographic +# strengths or algorithms. +# +# limited: These policy files contain more restricted cryptographic +# strengths, and are still available if your country or +# usage requires the traditional restrictive policy. +# +# The JDK JCE framework uses the unlimited policy files by default. +# However the user may explicitly choose a set either by defining the +# "crypto.policy" Security property or by installing valid JCE policy +# jar files into the traditional JDK installation location. To better +# support older JDK Update releases, the "crypto.policy" property is not +# defined by default. See below for more information. +# +# The following logic determines which policy files are used: +# +# refers to the directory where the JRE was +# installed and may be determined using the "java.home" +# System property. +# +# 1. If the Security property "crypto.policy" has been defined, +# then the following mechanism is used: +# +# The policy files are stored as jar files in subdirectories of +# /lib/security/policy. Each directory contains a complete +# set of policy files. +# +# The "crypto.policy" Security property controls the directory +# selection, and thus the effective cryptographic policy. +# +# The default set of directories is: +# +# limited | unlimited +# +# 2. If the "crypto.policy" property is not set and the traditional +# US_export_policy.jar and local_policy.jar files +# (e.g. limited/unlimited) are found in the legacy +# /lib/security directory, then the rules embedded within +# those jar files will be used. This helps preserve compatibility +# for users upgrading from an older installation. +# +# 3. If the jar files are not present in the legacy location +# and the "crypto.policy" Security property is not defined, +# then the JDK will use the unlimited settings (equivalent to +# crypto.policy=unlimited) +# +# Please see the JCA documentation for additional information on these +# files and formats. +# +# YOU ARE ADVISED TO CONSULT YOUR EXPORT/IMPORT CONTROL COUNSEL OR ATTORNEY +# TO DETERMINE THE EXACT REQUIREMENTS. +# +# Please note that the JCE for Java SE, including the JCE framework, +# cryptographic policy files, and standard JCE providers provided with +# the Java SE, have been reviewed and approved for export as mass market +# encryption item by the US Bureau of Industry and Security. +# +# Note: This property is currently used by the JDK Reference implementation. +# It is not guaranteed to be examined and used by other implementations. +# +crypto.policy=unlimited + +# +# The policy for the XML Signature secure validation mode. The mode is +# enabled by setting the property "org.jcp.xml.dsig.secureValidation" to +# true with the javax.xml.crypto.XMLCryptoContext.setProperty() method, +# or by running the code with a SecurityManager. +# +# Policy: +# Constraint {"," Constraint } +# Constraint: +# AlgConstraint | MaxTransformsConstraint | MaxReferencesConstraint | +# ReferenceUriSchemeConstraint | KeySizeConstraint | OtherConstraint +# AlgConstraint +# "disallowAlg" Uri +# MaxTransformsConstraint: +# "maxTransforms" Integer +# MaxReferencesConstraint: +# "maxReferences" Integer +# ReferenceUriSchemeConstraint: +# "disallowReferenceUriSchemes" String { String } +# KeySizeConstraint: +# "minKeySize" KeyAlg Integer +# OtherConstraint: +# "noDuplicateIds" | "noRetrievalMethodLoops" +# +# For AlgConstraint, Uri is the algorithm URI String that is not allowed. +# See the XML Signature Recommendation for more information on algorithm +# URI Identifiers. For KeySizeConstraint, KeyAlg is the standard algorithm +# name of the key type (ex: "RSA"). If the MaxTransformsConstraint, +# MaxReferencesConstraint or KeySizeConstraint (for the same key type) is +# specified more than once, only the last entry is enforced. +# +# Note: This property is currently used by the JDK Reference implementation. It +# is not guaranteed to be examined and used by other implementations. +# +jdk.xml.dsig.secureValidationPolicy=\ + disallowAlg http://www.w3.org/TR/1999/REC-xslt-19991116,\ + disallowAlg http://www.w3.org/2001/04/xmldsig-more#rsa-md5,\ + disallowAlg http://www.w3.org/2001/04/xmldsig-more#hmac-md5,\ + disallowAlg http://www.w3.org/2001/04/xmldsig-more#md5,\ + maxTransforms 5,\ + maxReferences 30,\ + disallowReferenceUriSchemes file http https,\ + minKeySize RSA 1024,\ + minKeySize DSA 1024,\ + minKeySize EC 224,\ + noDuplicateIds,\ + noRetrievalMethodLoops + +# +# Serialization process-wide filter +# +# A filter, if configured, is used by java.io.ObjectInputStream during +# deserialization to check the contents of the stream. +# A filter is configured as a sequence of patterns, each pattern is either +# matched against the name of a class in the stream or defines a limit. +# Patterns are separated by ";" (semicolon). +# Whitespace is significant and is considered part of the pattern. +# +# If the system property jdk.serialFilter is also specified, it supersedes +# the security property value defined here. +# +# If a pattern includes a "=", it sets a limit. +# If a limit appears more than once the last value is used. +# Limits are checked before classes regardless of the order in the sequence of patterns. +# If any of the limits are exceeded, the filter status is REJECTED. +# +# maxdepth=value - the maximum depth of a graph +# maxrefs=value - the maximum number of internal references +# maxbytes=value - the maximum number of bytes in the input stream +# maxarray=value - the maximum array length allowed +# +# Other patterns, from left to right, match the class or package name as +# returned from Class.getName. +# If the class is an array type, the class or package to be matched is the element type. +# Arrays of any number of dimensions are treated the same as the element type. +# For example, a pattern of "!example.Foo", rejects creation of any instance or +# array of example.Foo. +# +# If the pattern starts with "!", the status is REJECTED if the remaining pattern +# is matched; otherwise the status is ALLOWED if the pattern matches. +# If the pattern ends with ".**" it matches any class in the package and all subpackages. +# If the pattern ends with ".*" it matches any class in the package. +# If the pattern ends with "*", it matches any class with the pattern as a prefix. +# If the pattern is equal to the class name, it matches. +# Otherwise, the status is UNDECIDED. +# +# Primitive types are not configurable with this filter. +# +#jdk.serialFilter=pattern;pattern + +# +# RMI Registry Serial Filter +# +# The filter pattern uses the same format as jdk.serialFilter. +# This filter can override the builtin filter if additional types need to be +# allowed or rejected from the RMI Registry or to decrease limits but not +# to increase limits. +# If the limits (maxdepth, maxrefs, or maxbytes) are exceeded, the object is rejected. +# +# The maxdepth of any array passed to the RMI Registry is set to +# 10000. The maximum depth of the graph is set to 20. +# These limits can be reduced via the maxarray, maxdepth limits. +# +#sun.rmi.registry.registryFilter=pattern;pattern + +# +# Array construction of any component type, including subarrays and arrays of +# primitives, are allowed unless the length is greater than the maxarray limit. +# The filter is applied to each array element. +# +# The built-in filter allows subclasses of allowed classes and +# can approximately be represented as the pattern: +# +#sun.rmi.registry.registryFilter=\ +# maxarray=1000000;\ +# maxdepth=20;\ +# java.lang.String;\ +# java.lang.Number;\ +# java.lang.reflect.Proxy;\ +# java.rmi.Remote;\ +# sun.rmi.server.UnicastRef;\ +# sun.rmi.server.RMIClientSocketFactory;\ +# sun.rmi.server.RMIServerSocketFactory;\ +# java.rmi.activation.ActivationID;\ +# java.rmi.server.UID +# +# RMI Distributed Garbage Collector (DGC) Serial Filter +# +# The filter pattern uses the same format as jdk.serialFilter. +# This filter can override the builtin filter if additional types need to be +# allowed or rejected from the RMI DGC. +# +# The builtin DGC filter can approximately be represented as the filter pattern: +# +#sun.rmi.transport.dgcFilter=\ +# java.rmi.server.ObjID;\ +# java.rmi.server.UID;\ +# java.rmi.dgc.VMID;\ +# java.rmi.dgc.Lease;\ +# maxdepth=5;maxarray=10000 + +# CORBA ORBIorTypeCheckRegistryFilter +# Type check enhancement for ORB::string_to_object processing +# +# An IOR type check filter, if configured, is used by an ORB during +# an ORB::string_to_object invocation to check the veracity of the type encoded +# in the ior string. +# +# The filter pattern consists of a semi-colon separated list of class names. +# The configured list contains the binary class names of the IDL interface types +# corresponding to the IDL stub class to be instantiated. +# As such, a filter specifies a list of IDL stub classes that will be +# allowed by an ORB when an ORB::string_to_object is invoked. +# It is used to specify a white list configuration of acceptable +# IDL stub types which may be contained in a stringified IOR +# parameter passed as input to an ORB::string_to_object method. +# +# Note: This property is currently used by the JDK Reference implementation. +# It is not guaranteed to be examined and used by other implementations. +# +#com.sun.CORBA.ORBIorTypeCheckRegistryFilter=binary_class_name;binary_class_name + +# +# JCEKS Encrypted Key Serial Filter +# +# This filter, if configured, is used by the JCEKS KeyStore during the +# deserialization of the encrypted Key object stored inside a key entry. +# If not configured or the filter result is UNDECIDED (i.e. none of the patterns +# matches), the filter configured by jdk.serialFilter will be consulted. +# +# If the system property jceks.key.serialFilter is also specified, it supersedes +# the security property value defined here. +# +# The filter pattern uses the same format as jdk.serialFilter. The default +# pattern allows java.lang.Enum, java.security.KeyRep, java.security.KeyRep$Type, +# and javax.crypto.spec.SecretKeySpec and rejects all the others. +jceks.key.serialFilter = java.lang.Enum;java.security.KeyRep;\ + java.security.KeyRep$Type;javax.crypto.spec.SecretKeySpec;!* + +# +# Policies for distrusting Certificate Authorities (CAs). +# +# This is a comma separated value of one or more case-sensitive strings, each +# of which represents a policy for determining if a CA should be distrusted. +# The supported values are: +# +# +# SYMANTEC_TLS : Distrust TLS Server certificates anchored by a Symantec +# root CA and issued after April 16, 2019 unless issued by one of the +# following subordinate CAs which have a later distrust date: +# 1. Apple IST CA 2 - G1, SHA-256 fingerprint: +# AC2B922ECFD5E01711772FEA8ED372DE9D1E2245FCE3F57A9CDBEC77296A424B +# Distrust after December 31, 2019. +# 2. Apple IST CA 8 - G1, SHA-256 fingerprint: +# A4FE7C7F15155F3F0AEF7AAA83CF6E06DEB97CA3F909DF920AC1490882D488ED +# Distrust after December 31, 2019. +# Leading and trailing whitespace surrounding each value are ignored. +# Unknown values are ignored. If the property is commented out or set to the +# empty String, no policies are enforced. +# +# Note: This property is currently used by the JDK Reference implementation. +# It is not guaranteed to be supported by other SE implementations. Also, this +# property does not override other security properties which can restrict +# certificates such as jdk.tls.disabledAlgorithms or +# jdk.certpath.disabledAlgorithms; those restrictions are still enforced even +# if this property is not enabled. +# +jdk.security.caDistrustPolicies=SYMANTEC_TLS \ No newline at end of file diff --git a/src/test/munit/activemq-over-ssl-test-case.xml b/src/test/munit/activemq-over-ssl-test-case.xml index 543a0510..82f47181 100644 --- a/src/test/munit/activemq-over-ssl-test-case.xml +++ b/src/test/munit/activemq-over-ssl-test-case.xml @@ -20,19 +20,19 @@ - + - + - + @@ -41,15 +41,15 @@ - - + + - - + + @@ -92,12 +92,18 @@ + + + + + + + expectedException="java.security.KeyStoreException" ignore="true"> - - + + diff --git a/src/test/munit/reconnection/activemq-ssl-listener-reconnection-test-case.xml b/src/test/munit/reconnection/activemq-ssl-listener-reconnection-test-case.xml index d52bed52..c785bee6 100644 --- a/src/test/munit/reconnection/activemq-ssl-listener-reconnection-test-case.xml +++ b/src/test/munit/reconnection/activemq-ssl-listener-reconnection-test-case.xml @@ -22,9 +22,10 @@ - + + - + diff --git a/src/test/munit/xa/activemq-ssl-xa-test-case.xml b/src/test/munit/xa/activemq-ssl-xa-test-case.xml index 0f27bdb9..f232ba31 100644 --- a/src/test/munit/xa/activemq-ssl-xa-test-case.xml +++ b/src/test/munit/xa/activemq-ssl-xa-test-case.xml @@ -21,12 +21,13 @@ - + + - + diff --git a/src/test/resources/activemq-fips.xml b/src/test/resources/activemq-fips.xml index e9b9eae9..a11a9c71 100644 --- a/src/test/resources/activemq-fips.xml +++ b/src/test/resources/activemq-fips.xml @@ -51,7 +51,15 @@ + keyStore="tls/broker.bcfks" + keyStorePassword="password" + keyStoreType="BCFKS" + + trustStore="tls/client.bcfks" + trustStorePassword="password" + trustStoreType="BCFKS" + + secureRandomAlgorithm="default" /> @@ -104,7 +112,7 @@ http://activemq.apache.org/configuring-transports.html --> - + diff --git a/src/test/resources/activemq.xml b/src/test/resources/activemq.xml index 54a7c6cf..645e4312 100644 --- a/src/test/resources/activemq.xml +++ b/src/test/resources/activemq.xml @@ -104,7 +104,7 @@ http://activemq.apache.org/configuring-transports.html --> - + diff --git a/src/test/resources/tls/broker.bcfks b/src/test/resources/tls/broker.bcfks new file mode 100644 index 0000000000000000000000000000000000000000..a269340a38157d86611c0435408a2d176da472b1 GIT binary patch literal 3742 zcmV;P4q@>yf)1K6f(_j;fs_UbDuzgg_YDCB4KRU*Fk}V^Duzgg_YDCB3@}#&Kn&gV zNQ^J+fgDRw2j(tLp3SOfNC9O71OYEF5d;j@{C`(f zp#G6TquK2O0SE+w4MNH|ON`vZE6JF>F!@D89jM~jS5XotO*E$%#6_rSYl|(e%hHuot@*wD%@UL|SrRjv4E1xdgfiU$)IqWE?kSHZNlqEPOd@kL2 z9BTZU`m;0&bE{Uz)Rxt8#k3~qGVJX6E?va9fLY(kc=#F+uj(y39BhOs8;FKoNE%oq zDX!iKA*C;nJcm%4s6d1hSfK|WhKt4=yqP=((l_Szc7ZnZBROMycZ0S1p+Gi12wWzc z`S1$r4+Gvde}*Vp|7%AMaVQWuBi?p-O?X5%B)a4c41`X38_FS36R=st{^mPLDzW`)V&)(A(J zqXWqPU+sNb-M@eG5+7<^2+qn*0b0L>3xlEd3&v4*-a{ePZBPD184#`3)#;+Huq9nn zR8ZxHqW>^dw&5r?b_L#fiyQve*M6vNG49I~J>6LKB!GK`_Q&+PjNEad9A|r>z4U2% zSYM}xP&Ah`tU~9t#-vFBByT2^Y{Ft*sfp-0yc{mxFSb<_X}Qvds+;p%RY(1<@s*(= zszN*_jkWi=~|{)c8SH&Dj%h5Lz(mwW5rpkbt<)E#8 zgOI8j@_!r?C2IO$C&D_01ueyzrmZ2@x(Sut4m+*>+|tchM&0|z_fE)rUE&AWr3JGl zH#DP)7Z$}Po|}QmUnp`48&~~Z)p})v4~4|kC@@rQPWLg3RBnDHG1D6li{y~% zbB`YDjSIp~fY|3S!9DP!6oeV-n&J7&1BIUcZl0husxiuu`VL;HD0O@t3wxgbL)=I;v4kagM6)fN6-MpcZJX zdCBvpP<37zYJ|2FZyq{e;gh+?{lWZ%iSmuM=Qk{hYKK}4U$P1+fgabsi@o~d)px9P znX17Yw`@c*nyEQ&y2rCb82l_5#?4@$K+1l4?*RWR`igQgYq2+Rv-GOvfdn1UJMh^0 zrz3V8Xuoo3AcoeZYOuO{1Tg&oBL@cb3a}Lyj$Q@uY5L=J z9tyqzZ=KPsCkYEUjQ}~o_Lfi zZu`s!d}tb5-^23eql(nJ)t6kU9N##$fv`Q&-dYk{Nknn`7gQ;L0;c=c#7l}o1nlT) z>8tVV`MO(%P#ss&t(S#f-Vg@a1}oJv+QqZ<_*#hvccN=|t+FgaPeOsSDc0m{w;@4q zi#DHfFc_`>@M-*9jHlo_PW6x6qmtA+(WJG}6h+HwLD47qvLmAQI{f}3Zs@8NhSiOT zaTWo<`Q6K=4>jOSFPCQ}ZGyF8}H>aTm0HV4tPNt~G@7B1@$j&(J)l%L!-&ERTP&e+E( zS#E;7z^7pT|68|g3L6q-nqW=jRE zgr&?C@t?6r#CePii)Q6Tk*jBclzBk#!Gx()}07sCQmcq)h)00EVq=>Fa7RF>PP*3-q|9!OAXtswzgr~nb!9Ms3 zu!+d<^nTCp9|)>l|$M#wri(6fZ#)nbx~HArg0q8 zaliQ0jrinK3_J#R`NK$WE;6<{$^d!#jHEZ|HcvPI$K-gU07i?5N02Z}Qgx*es-P^l zgQv#=e$d8ZQ^GzHw6vgsd@#3MG#_$#4>_<>p*|x?XTfB=HXKk2K-Wi&Sd=9cPe2LZeo{f1zsiAA z-jT-)tU*;0@pDv3)umCSt--Di6*)(rJz!lU!(bP0f$@YCQ%ky9p;?{edn6F8Kd-hV z;}@fLC6Xhz&`cUYYZP1WkIoSC^-wCW_WhX=7BWlBu#5N>N%DOZdN-^w7_x+3?os6$ zBzH$1&@W>gr?gJ12=RiHd;D|`WpkzXtpNoSA7k*7uzP?8C$}Y1;W?D%{p^GK{DS4_ z;Z4#X%V4=m)pDR6Q^+c){F|sZ8Y2edo5wW4IQ{q>6;K+N&d++`BM&k`$m`;xWHD~j@t9KIK z4mn1yuTKg2%$UuUL7Kb_v7yNuhOfc7ByFn_=!&3Z*aG)YN8;N>hFHH)rD8wf=SczxI5bw@Y1pCje@L1YCGQMC=@8_l=ynz*G!Q^*yqVA3)*oqN~ge4a?SxfxwTUz)f{7yG?$(Jj2$Whh1^ydM=S{D2N z(l*=Y%yf3W&Qy2e%F-!%zai5#8k44``+q-lH8%7v$GVY_+RHJf?8Pp*j({^uIv|%~ z7x@bAdKRBkx20jJQyWX1`#~_P*)Prbs5Bz>EpX2iye)HQot$r@63dk;H78{pS|H>^ty5 zCtjw0e^~HjOgQR}`>x?}2qm$+SBgNBhd<_zlH_@>hO2oUbq%?1(09v`XvAK=jBVc< zm%s}38ohP2gWc?KAu9!Y0Fp*R1K33=m19>ui_%dH79{CDr1q?24&N2>c8eA1A}o2C zt@Hx(tgYab-Hsq!`pfU%+qAj6PdF0czZk(2HXB!DNhe8`FUm=}aAEyGXQXPsiyclM z-lK2gsq19D`Gctg+eDy_qr1MSX(-l1o_ zI-25e33`muNqiJ|>$z}3-?0G(V6G!DKbDk$_IR8m#mG`0=q3mA?8}fL1&CsSnVJ#D ziglmISB=q)gAHzQw6(m=X*sASanh|4hW0ZaX_WR2``OCL`@T>D;b7=66$~KpO^fRH zia{j~j&oCMC1$c7QEXRG=5PS|@ooTS*WiQQ6>?nX7Q+1Hke|Cf$~c!H&zD;)sngav zx1uLcYYGkua+)c%_%CfaRDaoIfC3Y4z$3z=FoCu(3pI0dn)GF31; zcV<{-R=%p|2bSj206>Vxi6k2&KAg?0q`ePmlrpK#)^My?TYsbKKNcuXv!GyM|2T`T I5|a8re{a?|r2qf` literal 0 HcmV?d00001 diff --git a/src/test/resources/tls/client.bcfks b/src/test/resources/tls/client.bcfks new file mode 100644 index 0000000000000000000000000000000000000000..04decbf841c0cbdd529d3527004bbf7c3ab9f471 GIT binary patch literal 3743 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 z zel5k_>2 zen08(*L`Td#HT&h(u^_ucO5RgtO^zCnRdZw`5_$?wH=mDBHajS&P)U8;c73!-ss2X znYSHbDO)dC2lIJ=$dNXmLG#Mot%LIcGMEdsuSa}F1>d1Ei3yJ;w6c0RpSBy8_1Tdg z2wGgJG4%_DRCd&iw7S{hLiXg02cp2d1P^QLVo2BP6loN={XgMl*I7YNu2`C2ZV z2xIIohZq6jw_Fv*3DgP5BcJSAsavm#OaF6Pe6g>K4XeWhYNL|r&l5yMkx0z5x7%#2 zxdT~?PQ!4D_`w~LF}DU48RHU7(Mkc<6_+PE*0{ycH3uR$aP<5&L zNQU&R|G)O;Q(Q*L0r`%Z{E9Xa!Hy}xiHH9hXbNwEVs^$V3+?#m>cRUgMDL4K5TCyxZsU596bb98SEqVl JChN)Jc;o*}B0B&8 literal 0 HcmV?d00001 From 7e82e4d0563b93df29bd2826d41eaac0d138458f Mon Sep 17 00:00:00 2001 From: Sorin Date: Wed, 29 Jan 2025 13:31:23 +0200 Subject: [PATCH 4/4] W-16889209 | fips client merge --- pom.xml | 10 + .../activemq/transport/tcp/SslTransport.java | 179 ---- .../activemq/transport/tcp/TcpTransport.java | 767 ------------------ .../jsse/provider/ProvSSLSocketDirect.java | 640 +++++++++++++++ .../activemq/ActiveMQConnectionProvider.java | 18 +- .../provider/loader/FirewallLoader.java | 2 +- .../munit/activemq-over-ssl-test-case.xml | 30 +- ...mq-ssl-listener-reconnection-test-case.xml | 2 +- .../munit/xa/activemq-ssl-xa-test-case.xml | 2 +- src/test/resources/activemq-fips.xml | 2 +- src/test/resources/activemq.xml | 2 +- 11 files changed, 672 insertions(+), 982 deletions(-) delete mode 100644 src/main/java/org/apache/activemq/transport/tcp/SslTransport.java delete mode 100644 src/main/java/org/apache/activemq/transport/tcp/TcpTransport.java create mode 100644 src/main/java/org/bouncycastle/jsse/provider/ProvSSLSocketDirect.java diff --git a/pom.xml b/pom.xml index 0907b81f..9e4759ff 100644 --- a/pom.xml +++ b/pom.xml @@ -135,6 +135,16 @@ provided + + + org.bouncycastle + bctls-jdk18on + 1.80 + provided + + + + diff --git a/src/main/java/org/apache/activemq/transport/tcp/SslTransport.java b/src/main/java/org/apache/activemq/transport/tcp/SslTransport.java deleted file mode 100644 index 548fab0f..00000000 --- a/src/main/java/org/apache/activemq/transport/tcp/SslTransport.java +++ /dev/null @@ -1,179 +0,0 @@ -package org.apache.activemq.transport.tcp; - -import java.io.IOException; -import java.net.Socket; -import java.net.SocketException; -import java.net.URI; -import java.net.UnknownHostException; -import java.security.cert.X509Certificate; -import java.util.Collections; - -import javax.net.ssl.SNIHostName; -import javax.net.ssl.SSLParameters; -import javax.net.ssl.SSLPeerUnverifiedException; -import javax.net.ssl.SSLSession; -import javax.net.ssl.SSLSocket; -import javax.net.ssl.SSLSocketFactory; - -import org.apache.activemq.command.ConnectionInfo; -import org.apache.activemq.wireformat.WireFormat; -public class SslTransport extends TcpTransport { - - /** - * Default to null as there are different defaults between server and client, initialiseSocket - * for more details - */ - private Boolean verifyHostName = null; - - /** - * Connect to a remote node such as a Broker. - * - * @param wireFormat The WireFormat to be used. - * @param socketFactory The socket factory to be used. Forcing SSLSockets - * for obvious reasons. - * @param remoteLocation The remote location. - * @param localLocation The local location. - * @param needClientAuth If set to true, the underlying socket will need - * client certificate authentication. - * @throws UnknownHostException If TcpTransport throws. - * @throws IOException If TcpTransport throws. - */ - @SuppressWarnings({ "unchecked", "rawtypes" }) - public SslTransport(WireFormat wireFormat, SSLSocketFactory socketFactory, URI remoteLocation, URI localLocation, boolean needClientAuth) throws IOException { - super(wireFormat, socketFactory, remoteLocation, localLocation); - if (this.socket != null) { - ((SSLSocket)this.socket).setNeedClientAuth(needClientAuth); - } - } - - @Override - protected void initialiseSocket(Socket sock) throws SocketException, IllegalArgumentException { - /** - * This needs to default to null because this transport class is used for both a server transport - * and a client connection and we have different defaults for both. - * If we default it to a value it might override the transport server setting - * that was configured inside TcpTransportServer (which sets a default to false for server side) - * - * The idea here is that if this is a server transport then verifyHostName will be set by the setter - * and not be null as TcpTransportServer will set a default value of false (or a user will set it - * using transport.verifyHostName) but if this is a client connection the value will be null by default - * and will stay null if the user uses socket.verifyHostName to set the value or doesn't use the setter - * If it is null then we can check socketOptions for the value and if not set there then we can - * just set a default of true as this will be a client - * - * Unfortunately we have to do this to stay consistent because every other SSL option on the client - * side can be configured using socket. but this particular option isn't actually part of the socket - * so it makes it tricky from a user standpoint. For consistency sake I think it makes sense to allow - * using the socket. prefix that has been established so users do not get confused (as well as - * allow using no prefix which just calls the setter directly) - * - * Because of this there are actually two ways a client can configure this value, the client can either use - * socket.verifyHostName= as mentioned or just simply use verifyHostName= without using the socket. - * prefix and that will also work as the value will be set using the setter on the transport - * - * example server transport config: - * ssl://localhost:61616?transport.verifyHostName=true - * - * example from client: - * ssl://localhost:61616?verifyHostName=true - * OR - * ssl://localhost:61616?socket.verifyHostName=true - * - */ - if (verifyHostName == null) { - //Check to see if the user included the value as part of socket options and if so then use that value - if (socketOptions != null && socketOptions.containsKey("verifyHostName")) { - verifyHostName = Boolean.parseBoolean(socketOptions.get("verifyHostName").toString()); - socketOptions.remove("verifyHostName"); - } else { - //If null and not set then this is a client so default to true - verifyHostName = true; - } - } - - // Lets try to configure the SSL SNI field. Handy in case your using - // a single proxy to route to different messaging apps. - final SSLParameters sslParams = new SSLParameters(); - if (remoteLocation != null) { - sslParams.setServerNames(Collections.singletonList(new SNIHostName(remoteLocation.getHost()))); - } - - if (verifyHostName) { - sslParams.setEndpointIdentificationAlgorithm("HTTPS"); - } - - if (remoteLocation != null || verifyHostName) { - // AMQ-8445 only set SSLParameters if it has been populated before - ((SSLSocket) this.socket).setSSLParameters(sslParams); - } - - super.initialiseSocket(sock); - } - - /** - * Initialize from a ServerSocket. No access to needClientAuth is given - * since it is already set within the provided socket. - * - * @param wireFormat The WireFormat to be used. - * @param socket The Socket to be used. Forcing SSL. - * @throws IOException If TcpTransport throws. - */ - public SslTransport(WireFormat wireFormat, SSLSocket socket) throws IOException { - super(wireFormat, socket); - } - - public SslTransport(WireFormat format, SSLSocket socket, - InitBuffer initBuffer) throws IOException { - super(format, socket, initBuffer); - } - - /** - * Overriding in order to add the client's certificates to ConnectionInfo - * Commmands. - * - * @param command The Command coming in. - */ - @Override - public void doConsume(Object command) { - // The instanceof can be avoided, but that would require modifying the - // Command clas tree and that would require too much effort right - // now. - if (command instanceof ConnectionInfo) { - ConnectionInfo connectionInfo = (ConnectionInfo)command; - connectionInfo.setTransportContext(getPeerCertificates()); - } - super.doConsume(command); - } - - public void setVerifyHostName(Boolean verifyHostName) { - this.verifyHostName = verifyHostName; - } - - /** - * @return peer certificate chain associated with the ssl socket - */ - @Override - public X509Certificate[] getPeerCertificates() { - - SSLSocket sslSocket = (SSLSocket)this.socket; - - SSLSession sslSession = sslSocket.getSession(); - - X509Certificate[] clientCertChain; - try { - clientCertChain = (X509Certificate[])sslSession.getPeerCertificates(); - } catch (SSLPeerUnverifiedException e) { - clientCertChain = null; - } - - return clientCertChain; - } - - /** - * @return pretty print of 'this' - */ - @Override - public String toString() { - return "ssl://" + socket.getInetAddress() + ":" + socket.getPort(); - } -} \ No newline at end of file diff --git a/src/main/java/org/apache/activemq/transport/tcp/TcpTransport.java b/src/main/java/org/apache/activemq/transport/tcp/TcpTransport.java deleted file mode 100644 index 069deeb9..00000000 --- a/src/main/java/org/apache/activemq/transport/tcp/TcpTransport.java +++ /dev/null @@ -1,767 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF 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 org.apache.activemq.transport.tcp; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.io.InterruptedIOException; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.Socket; -import java.net.SocketAddress; -import java.net.SocketException; -import java.net.SocketTimeoutException; -import java.net.URI; -import java.net.UnknownHostException; -import java.nio.ByteBuffer; -import java.security.cert.X509Certificate; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; - -import javax.net.SocketFactory; - -import org.apache.activemq.Service; -import org.apache.activemq.TransportLoggerSupport; -import org.apache.activemq.thread.TaskRunnerFactory; -import org.apache.activemq.transport.Transport; -import org.apache.activemq.transport.TransportThreadSupport; -import org.apache.activemq.util.InetAddressUtil; -import org.apache.activemq.util.IntrospectionSupport; -import org.apache.activemq.util.ServiceStopper; -import org.apache.activemq.wireformat.WireFormat; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * An implementation of the {@link Transport} interface using raw tcp/ip - */ -public class TcpTransport extends TransportThreadSupport implements Transport, Service, Runnable { - - private static final Logger LOG = LoggerFactory.getLogger(TcpTransport.class); - - protected final URI remoteLocation; - protected final URI localLocation; - protected final WireFormat wireFormat; - - protected int connectionTimeout = 30000; - protected int soTimeout; - protected int socketBufferSize = 64 * 1024; - protected int ioBufferSize = 8 * 1024; - protected boolean closeAsync=true; - protected Socket socket; - protected DataOutputStream dataOut; - protected DataInputStream dataIn; - protected TimeStampStream buffOut = null; - - protected final InitBuffer initBuffer; - - /** - * The Traffic Class to be set on the socket. - */ - protected int trafficClass = 0; - /** - * Keeps track of attempts to set the Traffic Class on the socket. - */ - private boolean trafficClassSet = false; - /** - * Prevents setting both the Differentiated Services and Type of Service - * transport options at the same time, since they share the same spot in - * the TCP/IP packet headers. - */ - protected boolean diffServChosen = false; - protected boolean typeOfServiceChosen = false; - /** - * trace=true -> the Transport stack where this TcpTransport - * object will be, will have a TransportLogger layer - * trace=false -> the Transport stack where this TcpTransport - * object will be, will NOT have a TransportLogger layer, and therefore - * will never be able to print logging messages. - * This parameter is most probably set in Connection or TransportConnector URIs. - */ - protected boolean trace = false; - /** - * Name of the LogWriter implementation to use. - * Names are mapped to classes in the resources/META-INF/services/org/apache/activemq/transport/logwriters directory. - * This parameter is most probably set in Connection or TransportConnector URIs. - */ - protected String logWriterName = TransportLoggerSupport.defaultLogWriterName; - /** - * Specifies if the TransportLogger will be manageable by JMX or not. - * Also, as long as there is at least 1 TransportLogger which is manageable, - * a TransportLoggerControl MBean will me created. - */ - protected boolean dynamicManagement = false; - /** - * startLogging=true -> the TransportLogger object of the Transport stack - * will initially write messages to the log. - * startLogging=false -> the TransportLogger object of the Transport stack - * will initially NOT write messages to the log. - * This parameter only has an effect if trace == true. - * This parameter is most probably set in Connection or TransportConnector URIs. - */ - protected boolean startLogging = true; - /** - * Specifies the port that will be used by the JMX server to manage - * the TransportLoggers. - * This should only be set in an URI by a client (producer or consumer) since - * a broker will already create a JMX server. - * It is useful for people who test a broker and clients in the same machine - * and want to control both via JMX; a different port will be needed. - */ - protected int jmxPort = 1099; - protected boolean useLocalHost = false; - protected int minmumWireFormatVersion; - protected SocketFactory socketFactory; - protected final AtomicReference stoppedLatch = new AtomicReference(); - protected volatile int receiveCounter; - - protected Map socketOptions; - private int soLinger = Integer.MIN_VALUE; - private Boolean keepAlive; - private Boolean tcpNoDelay; - private Thread runnerThread; - - /** - * Connect to a remote Node - e.g. a Broker - * - * @param wireFormat - * @param socketFactory - * @param remoteLocation - * @param localLocation - e.g. local InetAddress and local port - * @throws IOException - * @throws UnknownHostException - */ - public TcpTransport(WireFormat wireFormat, SocketFactory socketFactory, URI remoteLocation, - URI localLocation) throws UnknownHostException, IOException { - this.wireFormat = wireFormat; - this.socketFactory = socketFactory; - try { - this.socket = socketFactory.createSocket(); - } catch (SocketException e) { - this.socket = null; - } - this.remoteLocation = remoteLocation; - this.localLocation = localLocation; - this.initBuffer = null; - setDaemon(false); - } - - /** - * Initialize from a server Socket - * - * @param wireFormat - * @param socket - * @throws IOException - */ - public TcpTransport(WireFormat wireFormat, Socket socket) throws IOException { - this(wireFormat, socket, null); - } - - public TcpTransport(WireFormat wireFormat, Socket socket, InitBuffer initBuffer) throws IOException { - this.wireFormat = wireFormat; - this.socket = socket; - this.remoteLocation = null; - this.localLocation = null; - this.initBuffer = initBuffer; - setDaemon(true); - } - - /** - * A one way asynchronous send - */ - @Override - public void oneway(Object command) throws IOException { - checkStarted(); - wireFormat.marshal(command, dataOut); - dataOut.flush(); - } - - /** - * @return pretty print of 'this' - */ - @Override - public String toString() { - return "" + (socket.isConnected() ? "tcp://" + socket.getInetAddress() + ":" + socket.getPort() + "@" + socket.getLocalPort() - : (localLocation != null ? localLocation : remoteLocation)) ; - } - - /** - * reads packets from a Socket - */ - @Override - public void run() { - LOG.trace("TCP consumer thread for " + this + " starting"); - this.runnerThread=Thread.currentThread(); - try { - while (!isStopped() && !isStopping()) { - doRun(); - } - } catch (IOException e) { - stoppedLatch.get().countDown(); - onException(e); - } catch (Throwable e){ - stoppedLatch.get().countDown(); - IOException ioe=new IOException("Unexpected error occurred: " + e); - ioe.initCause(e); - onException(ioe); - }finally { - stoppedLatch.get().countDown(); - } - } - - protected void doRun() throws IOException { - try { - Object command = readCommand(); - doConsume(command); - } catch (SocketTimeoutException e) { - } catch (InterruptedIOException e) { - } - } - - protected Object readCommand() throws IOException { - return wireFormat.unmarshal(dataIn); - } - - // Properties - // ------------------------------------------------------------------------- - public String getDiffServ() { - // This is the value requested by the user by setting the Tcp Transport - // options. If the socket hasn't been created, then this value may not - // reflect the value returned by Socket.getTrafficClass(). - return Integer.toString(this.trafficClass); - } - - public void setDiffServ(String diffServ) throws IllegalArgumentException { - this.trafficClass = QualityOfServiceUtils.getDSCP(diffServ); - this.diffServChosen = true; - } - - public int getTypeOfService() { - // This is the value requested by the user by setting the Tcp Transport - // options. If the socket hasn't been created, then this value may not - // reflect the value returned by Socket.getTrafficClass(). - return this.trafficClass; - } - - public void setTypeOfService(int typeOfService) { - this.trafficClass = QualityOfServiceUtils.getToS(typeOfService); - this.typeOfServiceChosen = true; - } - - public boolean isTrace() { - return trace; - } - - public void setTrace(boolean trace) { - this.trace = trace; - } - - public String getLogWriterName() { - return logWriterName; - } - - public void setLogWriterName(String logFormat) { - this.logWriterName = logFormat; - } - - public boolean isDynamicManagement() { - return dynamicManagement; - } - - public void setDynamicManagement(boolean useJmx) { - this.dynamicManagement = useJmx; - } - - public boolean isStartLogging() { - return startLogging; - } - - public void setStartLogging(boolean startLogging) { - this.startLogging = startLogging; - } - - public int getJmxPort() { - return jmxPort; - } - - public void setJmxPort(int jmxPort) { - this.jmxPort = jmxPort; - } - - public int getMinmumWireFormatVersion() { - return minmumWireFormatVersion; - } - - public void setMinmumWireFormatVersion(int minmumWireFormatVersion) { - this.minmumWireFormatVersion = minmumWireFormatVersion; - } - - public boolean isUseLocalHost() { - return useLocalHost; - } - - /** - * Sets whether 'localhost' or the actual local host name should be used to - * make local connections. On some operating systems such as Macs its not - * possible to connect as the local host name so localhost is better. - */ - public void setUseLocalHost(boolean useLocalHost) { - this.useLocalHost = useLocalHost; - } - - public int getSocketBufferSize() { - return socketBufferSize; - } - - /** - * Sets the buffer size to use on the socket - */ - public void setSocketBufferSize(int socketBufferSize) { - this.socketBufferSize = socketBufferSize; - } - - public int getSoTimeout() { - return soTimeout; - } - - /** - * Sets the socket timeout - */ - public void setSoTimeout(int soTimeout) { - this.soTimeout = soTimeout; - } - - public int getConnectionTimeout() { - return connectionTimeout; - } - - /** - * Sets the timeout used to connect to the socket - */ - public void setConnectionTimeout(int connectionTimeout) { - this.connectionTimeout = connectionTimeout; - } - - public Boolean getKeepAlive() { - return keepAlive; - } - - /** - * Enable/disable TCP KEEP_ALIVE mode - */ - public void setKeepAlive(Boolean keepAlive) { - this.keepAlive = keepAlive; - } - - /** - * Enable/disable soLinger - * @param soLinger enabled if > -1, disabled if == -1, system default otherwise - */ - public void setSoLinger(int soLinger) { - this.soLinger = soLinger; - } - - public int getSoLinger() { - return soLinger; - } - - public Boolean getTcpNoDelay() { - return tcpNoDelay; - } - - /** - * Enable/disable the TCP_NODELAY option on the socket - */ - public void setTcpNoDelay(Boolean tcpNoDelay) { - this.tcpNoDelay = tcpNoDelay; - } - - /** - * @return the ioBufferSize - */ - public int getIoBufferSize() { - return this.ioBufferSize; - } - - /** - * @param ioBufferSize the ioBufferSize to set - */ - public void setIoBufferSize(int ioBufferSize) { - this.ioBufferSize = ioBufferSize; - } - - /** - * @return the closeAsync - */ - public boolean isCloseAsync() { - return closeAsync; - } - - /** - * @param closeAsync the closeAsync to set - */ - public void setCloseAsync(boolean closeAsync) { - this.closeAsync = closeAsync; - } - - // Implementation methods - // ------------------------------------------------------------------------- - protected String resolveHostName(String host) throws UnknownHostException { - if (isUseLocalHost()) { - String localName = InetAddressUtil.getLocalHostName(); - if (localName != null && localName.equals(host)) { - return "localhost"; - } - } - return host; - } - - /** - * Configures the socket for use - * - * @param sock the socket - * @throws SocketException, IllegalArgumentException if setting the options - * on the socket failed. - */ - protected void initialiseSocket(Socket sock) throws SocketException, IllegalArgumentException { - if (socketOptions != null) { - // copy the map as its used values is being removed when calling setProperties - // and we need to be able to set the options again in case socket is re-initailized - Map copy = new HashMap(socketOptions); - IntrospectionSupport.setProperties(socket, copy); - if (!copy.isEmpty()) { - throw new IllegalArgumentException("Invalid socket parameters: " + copy); - } - } - - try { - //only positive values are legal - if (socketBufferSize > 0) { - sock.setReceiveBufferSize(socketBufferSize); - sock.setSendBufferSize(socketBufferSize); - } else { - LOG.warn("Socket buffer size was set to {}; Skipping this setting as the size must be a positive number.", socketBufferSize); - } - } catch (SocketException se) { - LOG.warn("Cannot set socket buffer size = " + socketBufferSize); - LOG.debug("Cannot set socket buffer size. Reason: " + se.getMessage() + ". This exception is ignored.", se); - } - sock.setSoTimeout(soTimeout); - - if (keepAlive != null) { - sock.setKeepAlive(keepAlive.booleanValue()); - } - - if (soLinger > -1) { - sock.setSoLinger(true, soLinger); - } else if (soLinger == -1) { - sock.setSoLinger(false, 0); - } - if (tcpNoDelay != null) { - sock.setTcpNoDelay(tcpNoDelay.booleanValue()); - } - if (!this.trafficClassSet) { - this.trafficClassSet = setTrafficClass(sock); - } - } - - @Override - protected void doStart() throws Exception { - connect(); - stoppedLatch.set(new CountDownLatch(1)); - super.doStart(); - } - - protected void connect() throws Exception { - - if (socket == null && socketFactory == null) { - throw new IllegalStateException("Cannot connect if the socket or socketFactory have not been set"); - } - - InetSocketAddress localAddress = null; - InetSocketAddress remoteAddress = null; - - if (localLocation != null) { - localAddress = new InetSocketAddress(InetAddress.getByName(localLocation.getHost()), - localLocation.getPort()); - } - - if (remoteLocation != null) { - String host = resolveHostName(remoteLocation.getHost()); - remoteAddress = new InetSocketAddress(host, remoteLocation.getPort()); - } - // Set the traffic class before the socket is connected when possible so - // that the connection packets are given the correct traffic class. - this.trafficClassSet = setTrafficClass(socket); - - if (socket != null) { - - if (localAddress != null) { - socket.bind(localAddress); - } - - // If it's a server accepted socket.. we don't need to connect it - // to a remote address. - if (remoteAddress != null) { - if (connectionTimeout >= 0) { - socket.connect(remoteAddress, connectionTimeout); - } else { - socket.connect(remoteAddress); - } - } - - } else { - // For SSL sockets.. you can't create an unconnected socket :( - // This means the timout option are not supported either. - if (localAddress != null) { - socket = socketFactory.createSocket(remoteAddress.getAddress(), remoteAddress.getPort(), - localAddress.getAddress(), localAddress.getPort()); - } else { - socket = socketFactory.createSocket(remoteAddress.getAddress(), remoteAddress.getPort()); - } - } - - initialiseSocket(socket); - initializeStreams(); - } - - @Override - protected void doStop(ServiceStopper stopper) throws Exception { - if (LOG.isDebugEnabled()) { - LOG.debug("Stopping transport " + this); - } - - // Closing the streams flush the sockets before closing.. if the socket - // is hung.. then this hangs the close. - // closeStreams(); - if (socket != null) { - if (closeAsync) { - //closing the socket can hang also - final CountDownLatch latch = new CountDownLatch(1); - - // need a async task for this - final TaskRunnerFactory taskRunnerFactory = new TaskRunnerFactory(); - taskRunnerFactory.execute(new Runnable() { - @Override - public void run() { - LOG.trace("Closing socket {}", socket); - try { - socket.close(); - LOG.debug("Closed socket {}", socket); - } catch (IOException e) { - if (LOG.isDebugEnabled()) { - LOG.debug("Caught exception closing socket " + socket + ". This exception will be ignored.", e); - } - } finally { - latch.countDown(); - } - } - }); - - try { - latch.await(1,TimeUnit.SECONDS); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } finally { - taskRunnerFactory.shutdownNow(); - } - - } else { - // close synchronously - LOG.trace("Closing socket {}", socket); - try { - socket.close(); - LOG.debug("Closed socket {}", socket); - } catch (IOException e) { - if (LOG.isDebugEnabled()) { - LOG.debug("Caught exception closing socket " + socket + ". This exception will be ignored.", e); - } - } - } - } - } - - /** - * Override so that stop() blocks until the run thread is no longer running. - */ - @Override - public void stop() throws Exception { - super.stop(); - CountDownLatch countDownLatch = stoppedLatch.get(); - if (countDownLatch != null && Thread.currentThread() != this.runnerThread) { - countDownLatch.await(1,TimeUnit.SECONDS); - } - } - - protected void initializeStreams() throws Exception { - TcpBufferedInputStream buffIn = new TcpBufferedInputStream(socket.getInputStream(), ioBufferSize) { - @Override - public int read() throws IOException { - receiveCounter++; - return super.read(); - } - @Override - public int read(byte[] b, int off, int len) throws IOException { - receiveCounter++; - return super.read(b, off, len); - } - @Override - public long skip(long n) throws IOException { - receiveCounter++; - return super.skip(n); - } - @Override - protected void fill() throws IOException { - receiveCounter++; - super.fill(); - } - }; - //Unread the initBuffer that was used for protocol detection if it exists - //so the stream can start over - if (initBuffer != null) { - buffIn.unread(initBuffer.buffer.array()); - } - this.dataIn = new DataInputStream(buffIn); - TcpBufferedOutputStream outputStream = new TcpBufferedOutputStream(socket.getOutputStream(), ioBufferSize); - this.dataOut = new DataOutputStream(outputStream); - this.buffOut = outputStream; - - } - - protected void closeStreams() throws IOException { - if (dataOut != null) { - dataOut.close(); - } - if (dataIn != null) { - dataIn.close(); - } - } - - public void setSocketOptions(Map socketOptions) { - this.socketOptions = new HashMap(socketOptions); - } - - @Override - public String getRemoteAddress() { - if (socket != null) { - SocketAddress address = socket.getRemoteSocketAddress(); - if (address instanceof InetSocketAddress) { - return "tcp://" + ((InetSocketAddress)address).getAddress().getHostAddress() + ":" + ((InetSocketAddress)address).getPort(); - } else { - return "" + socket.getRemoteSocketAddress(); - } - } - return null; - } - - @Override - public T narrow(Class target) { - if (target == Socket.class) { - return target.cast(socket); - } else if ( target == TimeStampStream.class) { - return target.cast(buffOut); - } - return super.narrow(target); - } - - @Override - public int getReceiveCounter() { - return receiveCounter; - } - - public static class InitBuffer { - public final int readSize; - public final ByteBuffer buffer; - - public InitBuffer(int readSize, ByteBuffer buffer) { - if (buffer == null) { - throw new IllegalArgumentException("Null buffer not allowed."); - } - this.readSize = readSize; - this.buffer = buffer; - } - } - - /** - * @param sock The socket on which to set the Traffic Class. - * @return Whether or not the Traffic Class was set on the given socket. - * @throws SocketException if the system does not support setting the - * Traffic Class. - * @throws IllegalArgumentException if both the Differentiated Services and - * Type of Services transport options have been set on the same - * connection. - */ - private boolean setTrafficClass(Socket sock) throws SocketException, - IllegalArgumentException { - if (sock == null - || (!this.diffServChosen && !this.typeOfServiceChosen)) { - return false; - } - if (this.diffServChosen && this.typeOfServiceChosen) { - throw new IllegalArgumentException("Cannot set both the " - + " Differentiated Services and Type of Services transport " - + " options on the same connection."); - } - - sock.setTrafficClass(this.trafficClass); - - int resultTrafficClass = sock.getTrafficClass(); - if (this.trafficClass != resultTrafficClass) { - // In the case where the user has specified the ECN bits (e.g. in - // Type of Service) but the system won't allow the ECN bits to be - // set or in the case where setting the traffic class failed for - // other reasons, emit a warning. - if ((this.trafficClass >> 2) == (resultTrafficClass >> 2) - && (this.trafficClass & 3) != (resultTrafficClass & 3)) { - LOG.warn("Attempted to set the Traffic Class to " - + this.trafficClass + " but the result Traffic Class was " - + resultTrafficClass + ". Please check that your system " - + "allows you to set the ECN bits (the first two bits)."); - } else { - LOG.warn("Attempted to set the Traffic Class to " - + this.trafficClass + " but the result Traffic Class was " - + resultTrafficClass + ". Please check that your system " - + "supports java.net.setTrafficClass."); - } - return false; - } - // Reset the guards that prevent both the Differentiated Services - // option and the Type of Service option from being set on the same - // connection. - this.diffServChosen = false; - this.typeOfServiceChosen = false; - return true; - } - - @Override - public WireFormat getWireFormat() { - return wireFormat; - } - - @Override - public X509Certificate[] getPeerCertificates() { - return null; - } - - @Override - public void setPeerCertificates(X509Certificate[] certificates) { - } -} \ No newline at end of file diff --git a/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSocketDirect.java b/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSocketDirect.java new file mode 100644 index 00000000..db8e95f9 --- /dev/null +++ b/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSocketDirect.java @@ -0,0 +1,640 @@ +package org.bouncycastle.jsse.provider; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.net.SocketException; +import java.net.UnknownHostException; +import java.security.Principal; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.net.ssl.SSLParameters; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocket; + +import org.bouncycastle.jsse.BCApplicationProtocolSelector; +import org.bouncycastle.jsse.BCExtendedSSLSession; +import org.bouncycastle.jsse.BCSSLConnection; +import org.bouncycastle.jsse.BCSSLParameters; +import org.bouncycastle.jsse.BCX509Key; +import org.bouncycastle.tls.AlertDescription; +import org.bouncycastle.tls.SecurityParameters; +import org.bouncycastle.tls.TlsClientProtocol; +import org.bouncycastle.tls.TlsFatalAlert; +import org.bouncycastle.tls.TlsProtocol; +import org.bouncycastle.tls.TlsServerProtocol; + +public class ProvSSLSocketDirect + extends ProvSSLSocketBase + implements ProvTlsManager +{ + private static final Logger LOG = Logger.getLogger(ProvSSLSocketDirect.class.getName()); + + protected final AppDataInput appDataIn = new AppDataInput(); + protected final AppDataOutput appDataOut = new AppDataOutput(); + + protected final ContextData contextData; + protected final ProvSSLParameters sslParameters; + + protected String peerHost = null; + protected String peerHostSNI = null; + protected boolean enableSessionCreation = true; + protected boolean useClientMode = true; + + protected TlsProtocol protocol = null; + protected ProvTlsPeer protocolPeer = null; + protected ProvSSLConnection connection = null; + protected ProvSSLSessionHandshake handshakeSession = null; + + /** This constructor is the one used (only) by ProvSSLServerSocket */ + ProvSSLSocketDirect(ContextData contextData, boolean enableSessionCreation, + boolean useClientMode, ProvSSLParameters sslParameters) + { + this.contextData = contextData; + this.enableSessionCreation = enableSessionCreation; + this.useClientMode = useClientMode; + this.sslParameters = sslParameters; + } + + protected ProvSSLSocketDirect(ContextData contextData) + { + this.contextData = contextData; + this.sslParameters = contextData.getDefaultSSLParameters(useClientMode); + } + + protected ProvSSLSocketDirect(ContextData contextData, InetAddress address, int port, InetAddress clientAddress, int clientPort) + throws IOException + { + this.contextData = contextData; + this.sslParameters = contextData.getDefaultSSLParameters(useClientMode); + + implBind(clientAddress, clientPort); + implConnect(address, port); + } + + protected ProvSSLSocketDirect(ContextData contextData, InetAddress address, int port) throws IOException + { + this.contextData = contextData; + this.sslParameters = contextData.getDefaultSSLParameters(useClientMode); + + implConnect(address, port); + } + + protected ProvSSLSocketDirect(ContextData contextData, String host, int port, InetAddress clientAddress, int clientPort) + throws IOException, UnknownHostException + { + this.contextData = contextData; + this.sslParameters = contextData.getDefaultSSLParameters(useClientMode); + this.peerHost = host; + + implBind(clientAddress, clientPort); + implConnect(host, port); + } + + protected ProvSSLSocketDirect(ContextData contextData, String host, int port) throws IOException, UnknownHostException + { + this.contextData = contextData; + this.sslParameters = contextData.getDefaultSSLParameters(useClientMode); + this.peerHost = host; + + implConnect(host, port); + } + + public ContextData getContextData() + { + return contextData; + } + + public void checkClientTrusted(X509Certificate[] chain, String authType) throws IOException + { + try + { + contextData.getX509TrustManager().checkClientTrusted(chain.clone(), authType, this); + } + catch (CertificateException e) + { + throw new TlsFatalAlert(AlertDescription.certificate_unknown, e); + } + } + + public void checkServerTrusted(X509Certificate[] chain, String authType) throws IOException + { + try + { + contextData.getX509TrustManager().checkServerTrusted(chain.clone(), authType, this); + } + catch (CertificateException e) + { + throw new TlsFatalAlert(AlertDescription.certificate_unknown, e); + } + } + + public BCX509Key chooseClientKey(String[] keyTypes, Principal[] issuers) + { + return getContextData().getX509KeyManager().chooseClientKeyBC(keyTypes, JsseUtils.clone(issuers), this); + } + + public BCX509Key chooseServerKey(String[] keyTypes, Principal[] issuers) + { + return getContextData().getX509KeyManager().chooseServerKeyBC(keyTypes, JsseUtils.clone(issuers), this); + } + + @Override + public synchronized void close() throws IOException + { + if (protocol == null) + { + closeSocket(); + } + else + { + protocol.close(); + } + } + + @Override + public void connect(SocketAddress endpoint, int timeout) throws IOException + { + if (!(endpoint instanceof InetSocketAddress)) + { + throw new SocketException("Only InetSocketAddress is supported."); + } + + super.connect(endpoint, timeout); + + notifyConnected(); + } + + // An SSLSocket method from JDK 9 (and then 8u251), but also a BCSSLSocket method + public synchronized String getApplicationProtocol() + { + return null == connection ? null : connection.getApplicationProtocol(); + } + + public synchronized BCApplicationProtocolSelector getBCHandshakeApplicationProtocolSelector() + { + return sslParameters.getSocketAPSelector(); + } + + public synchronized BCExtendedSSLSession getBCHandshakeSession() + { + return handshakeSession; + } + + public BCExtendedSSLSession getBCSession() + { + return getSessionImpl(); + } + + public synchronized BCSSLConnection getConnection() + { + try + { + handshakeIfNecessary(false); + } + catch (IOException e) + { + LOG.log(Level.FINE, "Failed to establish connection", e); + } + + return connection; + } + + @Override + public synchronized String[] getEnabledCipherSuites() + { + return sslParameters.getCipherSuites(); + } + + @Override + public synchronized String[] getEnabledProtocols() + { + return sslParameters.getProtocols(); + } + + @Override + public synchronized boolean getEnableSessionCreation() + { + return enableSessionCreation; + } + + // An SSLSocket method from JDK 9 (and then 8u251), but also a BCSSLSocket method + public synchronized String getHandshakeApplicationProtocol() + { + return null == handshakeSession ? null : handshakeSession.getApplicationProtocol(); + } + + // An SSLSocket method from JDK 7 + public synchronized SSLSession getHandshakeSession() + { + return null == handshakeSession ? null : handshakeSession.getExportSSLSession(); + } + + @Override + public InputStream getInputStream() throws IOException + { + return appDataIn; + } + + @Override + public synchronized boolean getNeedClientAuth() + { + return sslParameters.getNeedClientAuth(); + } + + @Override + public OutputStream getOutputStream() throws IOException + { + return appDataOut; + } + + public synchronized BCSSLParameters getParameters() + { + return SSLParametersUtil.getParameters(sslParameters); + } + + @Override + public SSLSession getSession() + { + return getSessionImpl().getExportSSLSession(); + } + + // An SSLSocket method from JDK 6 + public synchronized SSLParameters getSSLParameters() + { + return SSLParametersUtil.getSSLParameters(sslParameters); + } + + @Override + public synchronized String[] getSupportedCipherSuites() + { + return contextData.getSupportedCipherSuites(); + } + + @Override + public synchronized String[] getSupportedProtocols() + { + return contextData.getSupportedProtocols(); + } + + public int getTransportID() + { + return System.identityHashCode(this); + } + + @Override + public synchronized boolean getUseClientMode() + { + return useClientMode; + } + + @Override + public synchronized boolean getWantClientAuth() + { + return sslParameters.getWantClientAuth(); + } + + public synchronized void setBCHandshakeApplicationProtocolSelector(BCApplicationProtocolSelector selector) + { + sslParameters.setSocketAPSelector(selector); + } + + public synchronized void setBCSessionToResume(BCExtendedSSLSession session) + { + if (null == session) + { + throw new NullPointerException("'session' cannot be null"); + } + if (!(session instanceof ProvSSLSession)) + { + throw new IllegalArgumentException("Session-to-resume must be a session returned from 'getBCSession'"); + } + if (null != protocol) + { + throw new IllegalArgumentException("Session-to-resume cannot be set after the handshake has begun"); + } + + sslParameters.setSessionToResume((ProvSSLSession)session); + } + + @Override + public synchronized void setEnabledCipherSuites(String[] suites) + { + sslParameters.setCipherSuites(suites); + } + + @Override + public synchronized void setEnabledProtocols(String[] protocols) + { + sslParameters.setProtocols(protocols); + } + + @Override + public synchronized void setEnableSessionCreation(boolean flag) + { + this.enableSessionCreation = flag; + } + + public synchronized void setHost(String host) + { + this.peerHost = host; + } + + @Override + public synchronized void setNeedClientAuth(boolean need) + { + sslParameters.setNeedClientAuth(need); + } + + public synchronized void setParameters(BCSSLParameters parameters) + { + SSLParametersUtil.setParameters(this.sslParameters, parameters); + } + + // An SSLSocket method from JDK 6 + public synchronized void setSSLParameters(SSLParameters sslParameters) + { + SSLParametersUtil.setSSLParameters(this.sslParameters, sslParameters); + } + + @Override + public synchronized void setUseClientMode(boolean useClientMode) + { + if (null != protocol) + { + throw new IllegalArgumentException("Mode cannot be changed after the initial handshake has begun"); + } + + if (this.useClientMode != useClientMode) + { + contextData.updateDefaultSSLParameters(sslParameters, useClientMode); + + this.useClientMode = useClientMode; + } + } + + @Override + public synchronized void setWantClientAuth(boolean want) + { + sslParameters.setWantClientAuth(want); + } + + @Override + public void shutdownInput() throws IOException + { + // TODO[tls13] + throw new UnsupportedOperationException("shutdownInput() not supported in TLS"); + } + + @Override + public void shutdownOutput() throws IOException + { + // TODO[tls13] + throw new UnsupportedOperationException("shutdownOutput() not supported in TLS"); + } + + @Override + public synchronized void startHandshake() throws IOException + { + startHandshake(true); + } + + protected void startHandshake(boolean resumable) throws IOException + { + if (protocol == null) + { + InputStream input = super.getInputStream(); + OutputStream output = super.getOutputStream(); + + if (this.useClientMode) + { + TlsClientProtocol clientProtocol = new ProvTlsClientProtocol(input, output, socketCloser); + clientProtocol.setResumableHandshake(resumable); + this.protocol = clientProtocol; + + ProvTlsClient client = new ProvTlsClient(this, sslParameters); + this.protocolPeer = client; + + clientProtocol.connect(client); + } + else + { + TlsServerProtocol serverProtocol = new ProvTlsServerProtocol(input, output, socketCloser); + serverProtocol.setResumableHandshake(resumable); + this.protocol = serverProtocol; + + ProvTlsServer server = new ProvTlsServer(this, sslParameters); + this.protocolPeer = server; + + serverProtocol.accept(server); + } + } + else if (protocol.isHandshaking()) + { + protocol.setResumableHandshake(resumable); + protocol.resumeHandshake(); + } + else + { + throw new UnsupportedOperationException("Renegotiation not supported"); + } + } + + public synchronized String getPeerHost() + { + return peerHost; + } + + public synchronized String getPeerHostSNI() + { + return peerHostSNI; + } + + public int getPeerPort() + { + return getPort(); + } + + public synchronized void notifyHandshakeComplete(ProvSSLConnection connection) + { + if (null != handshakeSession) + { + if (!handshakeSession.isValid()) + { + connection.getSession().invalidate(); + } + + handshakeSession.getJsseSecurityParameters().clear(); + } + + this.handshakeSession = null; + this.connection = connection; + + notifyHandshakeCompletedListeners(connection.getSession().exportSSLSession); + } + + public synchronized void notifyHandshakeSession(ProvSSLSessionContext sslSessionContext, + SecurityParameters securityParameters, JsseSecurityParameters jsseSecurityParameters, + ProvSSLSession resumedSession) + { + String peerHost = getPeerHost(); + int peerPort = getPeerPort(); + + if (null != resumedSession) + { + this.handshakeSession = new ProvSSLSessionResumed(sslSessionContext, peerHost, peerPort, securityParameters, + jsseSecurityParameters, resumedSession.getTlsSession(), resumedSession.getJsseSessionParameters()); + } + else + { + this.handshakeSession = new ProvSSLSessionHandshake(sslSessionContext, peerHost, peerPort, + securityParameters, jsseSecurityParameters); + } + } + + public synchronized String selectApplicationProtocol(List protocols) + { + return sslParameters.getSocketAPSelector().select(this, protocols); + } + + synchronized ProvSSLSession getSessionImpl() + { + getConnection(); + + return null == connection ? ProvSSLSession.NULL_SESSION : connection.getSession(); + } + + synchronized void handshakeIfNecessary(boolean resumable) throws IOException + { + if (protocol == null || protocol.isHandshaking()) + { + startHandshake(resumable); + } + } + + synchronized void notifyConnected() + { + if (JsseUtils.isNameSpecified(peerHost)) + { + this.peerHostSNI = peerHost; + return; + } + + InetAddress peerAddress = getInetAddress(); + if (null == peerAddress) + { + this.peerHostSNI = null; + return; + } + + /* + * TODO[jsse] If we could somehow access the 'originalHostName' of peerAddress, it would be + * usable as a default SNI host_name. + */ +// String originalHostName = peerAddress.holder().getOriginalHostName(); +// if (JsseUtils.isNameSpecified(originalHostName)) +// { +// this.peerHost = originalHostName; +// this.peerHostSNI = originalHostName; +// return; +// } + + if (useClientMode && provAssumeOriginalHostName) + { + String originalHostName = peerAddress.getHostName(); + + this.peerHost = originalHostName; + this.peerHostSNI = originalHostName; + return; + } + + if (!useClientMode) + { + this.peerHost = peerAddress.getHostAddress(); + } + else if (provJdkTlsTrustNameService) + { + this.peerHost = peerAddress.getHostName(); + } + else + { + this.peerHost = null; + } + + this.peerHostSNI = null; + } + + class AppDataInput extends InputStream + { + @Override + public int read() throws IOException + { + handshakeIfNecessary(true); + + byte[] buf = new byte[1]; + int ret = protocol.readApplicationData(buf, 0, 1); + return ret < 1 ? -1 : buf[0] & 0xFF; + } + + @Override + public int read(byte[] b, int off, int len) throws IOException + { + if (len < 1) + { + return 0; + } + + handshakeIfNecessary(true); + return protocol.readApplicationData(b, off, len); + } + + @Override + public int available() throws IOException + { + synchronized (ProvSSLSocketDirect.this) + { + return protocol == null + ? 0 + : protocol.applicationDataAvailable(); + } + } + + @Override + public void close() throws IOException + { + ProvSSLSocketDirect.this.close(); + } + } + + class AppDataOutput extends OutputStream + { + @Override + public void write(int b) throws IOException + { + write(new byte[]{ (byte)b }, 0, 1); + } + + @Override + public void write(byte[] b, int off, int len) throws IOException + { + if (len > 0) + { + handshakeIfNecessary(true); + protocol.writeApplicationData(b, off, len); + } + } + + @Override + public void close() throws IOException + { + ProvSSLSocketDirect.this.close(); + } + } +} \ No newline at end of file diff --git a/src/main/java/org/mule/extensions/jms/internal/connection/provider/activemq/ActiveMQConnectionProvider.java b/src/main/java/org/mule/extensions/jms/internal/connection/provider/activemq/ActiveMQConnectionProvider.java index bbd94594..e1c71f9c 100644 --- a/src/main/java/org/mule/extensions/jms/internal/connection/provider/activemq/ActiveMQConnectionProvider.java +++ b/src/main/java/org/mule/extensions/jms/internal/connection/provider/activemq/ActiveMQConnectionProvider.java @@ -89,6 +89,8 @@ public class ActiveMQConnectionProvider extends BaseConnectionProvider implement static final String ACTIVEMQ_VERSION = "5.15.16"; static final String BROKER_GA = "org.apache.activemq:activemq-broker"; static final String KAHA_DB_GA = "org.apache.activemq:activemq-kahadb-store"; + public static final String FIPS_140_2 = "fips140-2"; + public static final String MULE_SECURITY_MODEL = "mule.security.model"; /** * a provider for an {@link ActiveMQConnectionFactory} @@ -268,15 +270,16 @@ private boolean shouldUseSsl() { } protected void configureSSLContext() { + + ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader(); + // force loading of class from connector instead of the one from the library, because it uses reflection + ClassLoader firewallLoader = new FirewallLoader(currentClassLoader); + ClassLoader loader = new URLClassLoader(new URL[]{this.getClass().getProtectionDomain().getCodeSource().getLocation()}, firewallLoader); + Thread.currentThread().setContextClassLoader(loader); + try { if (tlsConfiguration != null) { SSLContext sslContext = tlsConfiguration.createSslContext(); - ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader(); - // force loading of class from connector instead of the one from the library, because it uses reflection - ClassLoader firewallLoader = new FirewallLoader(currentClassLoader); - ClassLoader loader = new URLClassLoader(new URL[]{this.getClass().getProtectionDomain().getCodeSource().getLocation()}, firewallLoader); - Thread.currentThread().setContextClassLoader(loader); - SslContext activeMQSslContext = new SslContext(); activeMQSslContext.setSSLContext(sslContext); SslContext.setCurrentSslContext(activeMQSslContext); @@ -285,6 +288,9 @@ protected void configureSSLContext() { } catch (KeyManagementException | NoSuchAlgorithmException | InvocationTargetException | IllegalAccessException | NoSuchMethodException e) { throw new JmsExtensionException("A problem occurred trying to configure SSL Options on ActiveMQ Connection", e); + } finally { + Thread.currentThread().setContextClassLoader(currentClassLoader); + } } diff --git a/src/main/java/org/mule/extensions/jms/internal/connection/provider/loader/FirewallLoader.java b/src/main/java/org/mule/extensions/jms/internal/connection/provider/loader/FirewallLoader.java index 254ec108..53a82cf2 100644 --- a/src/main/java/org/mule/extensions/jms/internal/connection/provider/loader/FirewallLoader.java +++ b/src/main/java/org/mule/extensions/jms/internal/connection/provider/loader/FirewallLoader.java @@ -5,7 +5,7 @@ public FirewallLoader(ClassLoader parent) { super(parent); } public Class loadClass(String name, boolean resolve) throws ClassNotFoundException { - if (name.equals("org.apache.activemq.transport.tcp.SslTransport") || name.equals("org.apache.activemq.transport.tcp.TcpTransport")) { + if (name.equals("org.bouncycastle.jsse.provider.ProvSSLSocketDirect")) { throw new ClassNotFoundException(); } return super.loadClass(name, resolve); diff --git a/src/test/munit/activemq-over-ssl-test-case.xml b/src/test/munit/activemq-over-ssl-test-case.xml index 82f47181..e2dea97a 100644 --- a/src/test/munit/activemq-over-ssl-test-case.xml +++ b/src/test/munit/activemq-over-ssl-test-case.xml @@ -20,19 +20,19 @@ - + - + - + @@ -40,16 +40,11 @@ - - - - - - - + + @@ -92,20 +87,5 @@ - - - - - - - - - - - - - diff --git a/src/test/munit/reconnection/activemq-ssl-listener-reconnection-test-case.xml b/src/test/munit/reconnection/activemq-ssl-listener-reconnection-test-case.xml index c785bee6..461eba82 100644 --- a/src/test/munit/reconnection/activemq-ssl-listener-reconnection-test-case.xml +++ b/src/test/munit/reconnection/activemq-ssl-listener-reconnection-test-case.xml @@ -25,7 +25,7 @@ - + diff --git a/src/test/munit/xa/activemq-ssl-xa-test-case.xml b/src/test/munit/xa/activemq-ssl-xa-test-case.xml index f232ba31..87ec1f01 100644 --- a/src/test/munit/xa/activemq-ssl-xa-test-case.xml +++ b/src/test/munit/xa/activemq-ssl-xa-test-case.xml @@ -27,7 +27,7 @@ - + diff --git a/src/test/resources/activemq-fips.xml b/src/test/resources/activemq-fips.xml index a11a9c71..850e2734 100644 --- a/src/test/resources/activemq-fips.xml +++ b/src/test/resources/activemq-fips.xml @@ -112,7 +112,7 @@ http://activemq.apache.org/configuring-transports.html --> - + diff --git a/src/test/resources/activemq.xml b/src/test/resources/activemq.xml index 645e4312..54a7c6cf 100644 --- a/src/test/resources/activemq.xml +++ b/src/test/resources/activemq.xml @@ -104,7 +104,7 @@ http://activemq.apache.org/configuring-transports.html --> - +