@@ -479,11 +479,29 @@ ssl_options.password = t0p$3kRe7
479
479
the chain of certificates presented by the peer
480
480
and if a trusted certificate is found, considers the peer trusted.
481
481
If no trusted and otherwise valid certificate is found, peer verification fails and client connection is closed
482
- with an error ("alert" in OpenSSL parlance).
482
+ with an error ("alert" in OpenSSL parlance) that says "Unknown CA" or similar. The alert
483
+ will be logged by the server with a message similar to this:
484
+
485
+ <pre class =" sourcecode ini" >
486
+ 2018-09-10 18:10:46.502 [info] < 0.902.0> TLS server generated SERVER ALERT: Fatal - Unknown CA
487
+ </pre >
483
488
</p >
484
489
<p >
485
490
Certificate validity is also checked at every step. Certificates that are expired
486
- and aren't yet valid will be rejected and skipped.
491
+ or aren't yet valid will be rejected. The TLS alert in that case will look something
492
+ like this:
493
+
494
+ <pre class =" sourcecode ini" >
495
+ 2018-09-10 18:11:05.168 [info] < 0.923.0> TLS server generated SERVER ALERT: Fatal - Certificate Expired
496
+ </pre >
497
+
498
+ </p >
499
+
500
+ <p >
501
+ The examples above demonstrate TLS alert messages logged by RabbitMQ running on Erlang/OTP 21.
502
+ Clients that perform peer verification will also raise alerts but may use different
503
+ error messages. <a href =" https://tools.ietf.org/html/rfc8446#section-6.2" >RFC 8446 section 6.2</a >
504
+ provides an overview of various alerts and what they mean.
487
505
</p >
488
506
</doc : subsection >
489
507
@@ -722,14 +740,11 @@ ssl_options.fail_if_no_peer_cert = false
722
740
import java.io.*;
723
741
import java.security.*;
724
742
725
-
726
743
import com.rabbitmq.client.*;
727
744
728
- public class Example1
729
- {
730
- public static void main(String[] args) throws Exception
731
- {
745
+ public class Example1 {
732
746
747
+ public static void main(String[] args) throws Exception {
733
748
ConnectionFactory factory = new ConnectionFactory();
734
749
factory.setHost(" localhost" );
735
750
factory.setPort(5671);
@@ -745,16 +760,14 @@ public class Example1
745
760
channel.queueDeclare(" rabbitmq-java-test" , false, true, true, null);
746
761
channel.basicPublish("" , " rabbitmq-java-test" , null, " Hello, World" .getBytes());
747
762
748
-
749
763
GetResponse chResponse = channel.basicGet(" rabbitmq-java-test" , false);
750
- if(chResponse == null) {
764
+ if (chResponse == null) {
751
765
System.out.println(" No message retrieved" );
752
766
} else {
753
767
byte[] body = chResponse.getBody();
754
- System.out.println(" Recieved : " + new String(body));
768
+ System.out.println(" Received : " + new String(body));
755
769
}
756
770
757
-
758
771
channel.close();
759
772
conn.close();
760
773
}
@@ -792,7 +805,7 @@ keytool -import -alias server1 -file /path/to/server/certificate.pem -keystore /
792
805
<code >keytool</code > will confirm that the certificate is trusted and ask for a password.
793
806
</p >
794
807
<p >
795
- We then use our client certificate and key in a <code >PKCS#12</code > file as
808
+ The client certificate and key in a <code >PKCS#12</code > file are then used as
796
809
already shown above.
797
810
</p >
798
811
<p >
@@ -806,12 +819,9 @@ import javax.net.ssl.*;
806
819
807
820
import com.rabbitmq.client.*;
808
821
822
+ public class Example2 {
809
823
810
- public class Example2
811
- {
812
- public static void main(String[] args) throws Exception
813
- {
814
-
824
+ public static void main(String[] args) throws Exception {
815
825
char[] keyPassphrase = " MySecretPassword" .toCharArray();
816
826
KeyStore ks = KeyStore.getInstance(" PKCS12" );
817
827
ks.load(new FileInputStream(" /path/to/client_key.p12" ), keyPassphrase);
@@ -826,30 +836,29 @@ public class Example2
826
836
TrustManagerFactory tmf = TrustManagerFactory.getInstance(" SunX509" );
827
837
tmf.init(tks);
828
838
829
- SSLContext c = SSLContext.getInstance(" TLSv1.1 " );
839
+ SSLContext c = SSLContext.getInstance(" TLSv1.2 " );
830
840
c.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
831
841
832
842
ConnectionFactory factory = new ConnectionFactory();
833
843
factory.setHost(" localhost" );
834
844
factory.setPort(5671);
835
845
factory.useSslProtocol(c);
846
+ factory.enableHostnameVerification();
836
847
837
848
Connection conn = factory.newConnection();
838
849
Channel channel = conn.createChannel();
839
850
840
851
channel.queueDeclare(" rabbitmq-java-test" , false, true, true, null);
841
852
channel.basicpublish("" , " rabbitmq-java-test" , null, " Hello, World" .getBytes());
842
853
843
-
844
854
GetResponse chResponse = channel.basicGet(" rabbitmq-java-test" , false);
845
- if(chResponse == null) {
855
+ if (chResponse == null) {
846
856
System.out.println(" No message retrieved" );
847
857
} else {
848
858
byte[] body = chResponse.getBody();
849
- System.out.println(" Recieved : " + new String(body));
859
+ System.out.println(" Received : " + new String(body));
850
860
}
851
861
852
-
853
862
channel.close();
854
863
conn.close();
855
864
}
@@ -861,6 +870,86 @@ public class Example2
861
870
a RabbitMQ node with a certificate that has not been imported
862
871
into the key store and watch the connection fail.
863
872
</p >
873
+
874
+ <h4 ><a class =" anchor" href =" #java-client-hostname-verification" >Server Hostname Verification</a ></h4 >
875
+ <p >
876
+ Hostname verification must be enabled separately using the
877
+ <code >ConnectionFactory#enableHostnameVerification()</code > method. This is done in the example
878
+ above, for instance:
879
+
880
+ <pre class =" sourcecode java" >
881
+ import java.io.*;
882
+ import java.security.*;
883
+ import javax.net.ssl.*;
884
+
885
+ import com.rabbitmq.client.*;
886
+
887
+ public class Example2 {
888
+
889
+ public static void main(String[] args) throws Exception {
890
+ char[] keyPassphrase = " MySecretPassword" .toCharArray();
891
+ KeyStore ks = KeyStore.getInstance(" PKCS12" );
892
+ ks.load(new FileInputStream(" /path/to/client_key.p12" ), keyPassphrase);
893
+
894
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance(" SunX509" );
895
+ kmf.init(ks, passphrase);
896
+
897
+ char[] trustPassphrase = " rabbitstore" .toCharArray();
898
+ KeyStore tks = KeyStore.getInstance(" JKS" );
899
+ tks.load(new FileInputStream(" /path/to/trustStore" ), trustPassphrase);
900
+
901
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance(" SunX509" );
902
+ tmf.init(tks);
903
+
904
+ SSLContext c = SSLContext.getInstance(" TLSv1.2" );
905
+ c.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
906
+
907
+ ConnectionFactory factory = new ConnectionFactory();
908
+ factory.setHost(" localhost" );
909
+ factory.setPort(5671);
910
+ factory.useSslProtocol(c);
911
+ factory.enableHostnameVerification();
912
+
913
+ // this connection will both perform peer verification
914
+ // and server hostname verification
915
+ Connection conn = factory.newConnection();
916
+
917
+ // snip ...
918
+ }
919
+ }</pre >
920
+
921
+ This will verify
922
+ that the server certificate has been issued for the hostname the
923
+ client is connecting to. Unlike certificate chain verification, this feature
924
+ is client-specific (not usually performed by the server).
925
+ </p >
926
+
927
+ <p >
928
+ With JDK 6, it is necessary to add a dependency on
929
+ <a href =" https://hc.apache.org/" >Apache Commons HttpClient</a > for hostname verification to work, e.g. with Maven:
930
+
931
+ <pre class =" sourcecode xml" >
932
+ < !-- Maven dependency to add for hostname verification on JDK 6 -->
933
+ < dependency>
934
+ < groupId> org.apache.httpcomponents< /groupId>
935
+ < artifactId> httpclient< /artifactId>
936
+ < version> 4.5.6< /version>
937
+ < /dependency>
938
+ </pre >
939
+
940
+ With Gradle:
941
+
942
+ <pre class =" sourcecode groovy" >
943
+ // Gradle dependency to add for hostname verification on JDK 6
944
+ compile group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.5.6'
945
+ </pre >
946
+ </p >
947
+ <p >
948
+ Alternatively with JDK 6
949
+ <code >ConnectionFactory#enableHostnameVerification(HostnameVerifier)</code >
950
+ can be provided a <code >HostnameVerifier</code > instance of choice.
951
+ </p >
952
+
864
953
</doc : subsection >
865
954
866
955
<doc : subsection name =" tls-versions-java-client" >
0 commit comments