使用证书身份验证进行任何连接尝试时,RabbitMQ SSL握手失败

时间:2014-12-29 16:51:47

标签: java ssl rabbitmq

我目前正在尝试迁移某些Java组件,以便通过SSL客户端证书而不是PLAIN方法执行RabbitMQ连接身份验证,但是几天后,由于所有Java组件连接尝试都是遇到握手错误。 不幸的是,调查RabbitMQ: handshake error when attempting to use SSL certificatesRabbitMQ SSL giving handshake failure when using SpringAMQP并未对我产生任何结果。

我努力做这项工作的环境是一个继承的"运行Ubuntu LTS 14.04的VirtualBox VM代表了我想要部署的环境。

rabbitmqctl报告的输出如下:

Status of node 'rabbit@developer-VirtualBox' ...
[{pid,23352},
 {running_applications,
     [{rabbitmq_management,"RabbitMQ Management Console","3.4.2"},
      {rabbitmq_web_dispatch,"RabbitMQ Web Dispatcher","3.4.2"},
      {webmachine,"webmachine","1.10.3-rmq3.4.2-gite9359c7"},
      {mochiweb,"MochiMedia Web Server","2.7.0-rmq3.4.2-git680dba8"},
      {rabbitmq_management_agent,"RabbitMQ Management Agent","3.4.2"},
      {rabbit,"RabbitMQ","3.4.2"},
      {ssl,"Erlang/OTP SSL application","5.3.2"},
      {public_key,"Public key infrastructure","0.21"},
      {crypto,"CRYPTO version 2","3.2"},
      {asn1,"The Erlang ASN1 compiler version 2.0.4","2.0.4"},
      {os_mon,"CPO  CXC 138 46","2.2.14"},
      {inets,"INETS  CXC 138 49","5.9.7"},
      {rabbitmq_auth_mechanism_ssl,
          "RabbitMQ SSL authentication (SASL EXTERNAL)","3.4.2"},
      {amqp_client,"RabbitMQ AMQP Client","3.4.2"},
      {xmerl,"XML parser","1.3.5"},
      {mnesia,"MNESIA  CXC 138 12","4.11"},
      {sasl,"SASL  CXC 138 11","2.3.4"},
      {stdlib,"ERTS  CXC 138 10","1.19.4"},
      {kernel,"ERTS  CXC 138 10","2.16.4"}]},
 {os,{unix,linux}},
 {erlang_version,
     "Erlang R16B03 (erts-5.10.4) [source] [64-bit] [async-threads:30] [kernel-poll:true]\n"},
 {memory,
     [{total,42662672},
      {connection_readers,0},
      {connection_writers,0},
      {connection_channels,0},
      {connection_other,5264},
      {queue_procs,2632},
      {queue_slave_procs,0},
      {plugins,411368},
      {other_proc,14374616},
      {mnesia,59360},
      {mgmt_db,124224},
      {msg_index,34312},
      {other_ets,1135040},
      {binary,42680},
      {code,21795549},
      {atom,793505},
      {other_system,3884122}]},
 {alarms,[]},
 {listeners,[{clustering,25672,"::"},{amqp,5672,"::"},{'amqp/ssl',5671,"::"}]},
 {vm_memory_high_watermark,0.4},
 {vm_memory_limit,1658211532},
 {disk_free_limit,50000000},
 {disk_free,43703377920},
 {file_descriptors,
     [{total_limit,924},{total_used,4},{sockets_limit,829},{sockets_used,2}]},
 {processes,[{limit,1048576},{used,191}]},
 {run_queue,0},
 {uptime,12}]

Cluster status of node 'rabbit@developer-VirtualBox' ...
[{nodes,[{disc,['rabbit@developer-VirtualBox']}]},
 {running_nodes,['rabbit@developer-VirtualBox']},
 {cluster_name,<<"rabbit@developer-VirtualBox">>},
 {partitions,[]}]

Application environment of node 'rabbit@developer-VirtualBox' ...
[{amqp_client,[{prefer_ipv6,false},{ssl_options,[]}]},
 {asn1,[]},
 {crypto,[]},
 {inets,[]},
 {kernel,
     [{error_logger,tty},
      {inet_default_connect_options,[{nodelay,true}]},
      {inet_dist_listen_max,25672},
      {inet_dist_listen_min,25672}]},
 {mnesia,[{dir,"/var/lib/rabbitmq/mnesia/rabbit@developer-VirtualBox"}]},
 {mochiweb,[]},
 {os_mon,
     [{start_cpu_sup,false},
      {start_disksup,false},
      {start_memsup,false},
      {start_os_sup,false}]},
 {public_key,[]},
 {rabbit,
     [{auth_backends,[rabbit_auth_backend_internal]},
      {auth_mechanisms,['EXTERNAL']},
      {backing_queue_module,rabbit_variable_queue},
      {channel_max,0},
      {cluster_keepalive_interval,10000},
      {cluster_nodes,{[],disc}},
      {cluster_partition_handling,ignore},
      {collect_statistics,fine},
      {collect_statistics_interval,5000},
      {default_permissions,[<<".*">>,<<".*">>,<<".*">>]},
      {default_user,<<"guest">>},
      {default_user_tags,[administrator]},
      {default_vhost,<<"/">>},
      {delegate_count,16},
      {disk_free_limit,50000000},
      {enabled_plugins_file,"/etc/rabbitmq/enabled_plugins"},
      {error_logger,
          {file,"/var/log/rabbitmq/rabbit@developer-VirtualBox.log"}},
      {frame_max,131072},
      {halt_on_upgrade_failure,true},
      {handshake_timeout,10000},
      {heartbeat,580},
      {hipe_compile,false},
      {hipe_modules,
          [rabbit_reader,rabbit_channel,gen_server2,rabbit_exchange,
           rabbit_command_assembler,rabbit_framing_amqp_0_9_1,rabbit_basic,
           rabbit_event,lists,queue,priority_queue,rabbit_router,rabbit_trace,
           rabbit_misc,rabbit_binary_parser,rabbit_exchange_type_direct,
           rabbit_guid,rabbit_net,rabbit_amqqueue_process,
           rabbit_variable_queue,rabbit_binary_generator,rabbit_writer,
           delegate,gb_sets,lqueue,sets,orddict,rabbit_amqqueue,
           rabbit_limiter,gb_trees,rabbit_queue_index,
           rabbit_exchange_decorator,gen,dict,ordsets,file_handle_cache,
           rabbit_msg_store,array,rabbit_msg_store_ets_index,rabbit_msg_file,
           rabbit_exchange_type_fanout,rabbit_exchange_type_topic,mnesia,
           mnesia_lib,rpc,mnesia_tm,qlc,sofs,proplists,credit_flow,pmon,
           ssl_connection,tls_connection,ssl_record,tls_record,gen_fsm,ssl]},
      {log_levels,[{connection,info}]},
      {loopback_users,[<<"guest">>]},
      {mnesia_table_loading_timeout,30000},
      {msg_store_file_size_limit,16777216},
      {msg_store_index_module,rabbit_msg_store_ets_index},
      {plugins_dir,
          "/usr/lib/rabbitmq/lib/rabbitmq_server-3.4.2/sbin/../plugins"},
      {plugins_expand_dir,
          "/var/lib/rabbitmq/mnesia/rabbit@developer-VirtualBox-plugins-expand"},
      {queue_index_max_journal_entries,65536},
      {reverse_dns_lookups,false},
      {sasl_error_logger,
          {file,"/var/log/rabbitmq/rabbit@developer-VirtualBox-sasl.log"}},
      {server_properties,[]},
      {ssl_allow_poodle_attack,false},
      {ssl_apps,[asn1,crypto,public_key,ssl]},
      {ssl_cert_login_from,distinguished_name},
      {ssl_handshake_timeout,5000},
      {ssl_listeners,[5671]},
      {ssl_options,
          [{cacertfile,"/home/developer/rabbitmqcert/devcafiles/cacert.pem"},
           {certfile,"/home/developer/rabbitmqcert/rabbitmq.public.pem"},
           {keyfile,"/home/developer/rabbitmqcert/rabbitmq.private.pem"},
           {verify,verify_peer},
           {ssl_cert_login_from,organization},
           {fail_if_no_peer_cert,true}]},
      {tcp_listen_options,
          [binary,
           {packet,raw},
           {reuseaddr,true},
           {backlog,128},
           {nodelay,true},
           {linger,{true,0}},
           {exit_on_close,false}]},
      {tcp_listeners,[5672]},
      {trace_vhosts,[]},
      {vm_memory_high_watermark,0.4},
      {vm_memory_high_watermark_paging_ratio,0.5}]},
 {rabbitmq_auth_mechanism_ssl,[{name_from,distinguished_name}]},
 {rabbitmq_management,
     [{http_log_dir,none},
      {listener,[{port,15672}]},
      {load_definitions,none},
      {rates_mode,basic},
      {sample_retention_policies,
          [{global,[{605,5},{3660,60},{29400,600},{86400,1800}]},
           {basic,[{605,5},{3600,60}]},
           {detailed,[{10,5}]}]}]},
 {rabbitmq_management_agent,[]},
 {rabbitmq_web_dispatch,[]},
 {sasl,[{errlog_type,error},{sasl_error_logger,false}]},
 {ssl,
     [{protocol_version,['tlsv1.2','tlsv1.1',tlsv1,sslv3]},
      {versions,['tlsv1.2','tlsv1.1']}]},
 {stdlib,[]},
 {webmachine,[{error_handler,rabbit_webmachine_error_handler}]},
 {xmerl,[]}]

Connections:

Channels:

Queues on /:

Exchanges on /:
name    type    durable auto_delete internal    arguments   policy
    direct  true    false   false   []  
amq.direct  direct  true    false   false   []  
amq.fanout  fanout  true    false   false   []  
amq.headers headers true    false   false   []  
amq.match   headers true    false   false   []  
amq.rabbitmq.log    topic   true    false   true    []  
amq.rabbitmq.trace  topic   true    false   true    []  
amq.topic   topic   true    false   false   []  

Bindings on /:

Consumers on /:

Permissions on /:
user    configure   write   read
O=dev,CN=rules  .*  .*  .*
guest   .*  .*  .*

Policies on /:

Parameters on /:

通过它,我可以看到:

  • _rabbitmq_auth_mechanism_ssl_插件已激活
  • 我正在侦听端口5671上的SSL连接
  • 唯一接受的身份验证机制是EXTERNAL
  • 我只接受TLS v1.1和TLS v1.2
  • 有一个用户_O = dev,CN = rules_ defined,与客户端证书中的主题相匹配。此用户没有关联密码(使用_sudo rabbitmqctl clear_password清除它&#34; O = dev,CN =规则&#34; _并且管理屏幕反映了该信息)
  • CA证书文件从_ / home / developer / rabbitmqcert / devcafiles / cacert.pem_中读取。这对应于为开发目的而创建的CA,其中使用的所有公钥(服务器和客户端等)都由其签名

为了简单(和理智),我尝试使用以下Java代码连接到RabbitMQ实例:

package com.rabbitmq.sample;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.DefaultSaslConfig;
import com.rabbitmq.client.QueueingConsumer;

public class CertificateAuthenticatedRabbitMQClientExample {

    private static final String CLIENT_CERTIFICATE_PASSWORD = "MySecretPassword";
    private static final String QUEUE_USED = "sampleQueue";
    public static void main(String[] args) throws UnrecoverableKeyException, NoSuchAlgorithmException, KeyStoreException, IOException, CertificateException, KeyManagementException, InterruptedException {
        SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
        KeyManager[] clientKeyManagerList = null;
        try(FileInputStream clientCertificateInputStream = new FileInputStream(new File("/home/developer/rabbitmqcert/ruleprocessing.password.p12"))) {
            KeyStore clientKeStore = KeyStore.getInstance("PKCS12");                                        //Create a clean KeyStore
            clientKeStore.load(clientCertificateInputStream, CLIENT_CERTIFICATE_PASSWORD.toCharArray());    //Load the client's certificate into the keystore
            KeyManagerFactory clientSSLKeyManagerFactory = KeyManagerFactory.getInstance("SunX509");
            clientSSLKeyManagerFactory.init(clientKeStore, CLIENT_CERTIFICATE_PASSWORD.toCharArray());
            clientKeyManagerList = clientSSLKeyManagerFactory.getKeyManagers();                             //Get list of key managers (in essence, only the keystore with the client certificate)
        }
        TrustManager[] clientTrustManagerList = {
          new X509TrustManager() {
              //Dummy trust store that trusts any server you connect to.
              //For demo purposes only
              @Override
              public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {}
              @Override
              public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {}
              @Override
              public X509Certificate[] getAcceptedIssuers() { return null;}
          }
        };
        sslContext.init(clientKeyManagerList, clientTrustManagerList, null);        //Initialize SSL context with the key and trust managers we've created/loaded before

        ConnectionFactory rabbitMqConnectionFactory = new ConnectionFactory();      //Create factory
        rabbitMqConnectionFactory.setHost("localhost");
        rabbitMqConnectionFactory.setPort(5671);
        rabbitMqConnectionFactory.setSaslConfig(DefaultSaslConfig.EXTERNAL);        //Set authentication method as SSL auth
        rabbitMqConnectionFactory.useSslProtocol(sslContext);                       //Set the created SSL context as the one to use
        Connection rabbitMqOutboundConnection = null;
        Channel rabbitMqOutboundChannel = null;
        try {
            rabbitMqOutboundConnection = rabbitMqConnectionFactory.newConnection();
            rabbitMqOutboundChannel = rabbitMqOutboundConnection.createChannel();
            rabbitMqOutboundChannel.queueDeclare(QUEUE_USED, false, false, false, null);
            rabbitMqOutboundChannel.basicPublish("", QUEUE_USED, null, "This is a sample message".getBytes());
            System.out.println("Message successfully sent to queue");
        }finally{
            if(rabbitMqOutboundChannel != null) {
                rabbitMqOutboundChannel.close();
            }
            if(rabbitMqOutboundConnection != null) {
                rabbitMqOutboundConnection.close();
            }
        }
        Connection rabbitMqInboundConnection = null;
        Channel rabbitMqInboundChannel = null;
        try {
            rabbitMqInboundConnection = rabbitMqConnectionFactory.newConnection();
            rabbitMqInboundChannel = rabbitMqInboundConnection.createChannel();
            rabbitMqInboundChannel.queueDeclare(QUEUE_USED, false, false, false, null);
            QueueingConsumer rabbitMqQueueConsumer = new QueueingConsumer(rabbitMqInboundChannel);
            rabbitMqInboundChannel.basicConsume(QUEUE_USED, true, rabbitMqQueueConsumer);
            QueueingConsumer.Delivery deliveryResult = rabbitMqQueueConsumer.nextDelivery();
            System.out.println("Message read from the queue: " + new String(deliveryResult.getBody()));
        }finally{
            if(rabbitMqInboundChannel != null) {
                rabbitMqInboundChannel.close();
            }
            if(rabbitMqInboundConnection != null) {
                rabbitMqInboundConnection.close();
            }
        }
    }

}

然而,我总是在线程&#34; main&#34;中遇到 Exception。 java.net.SocketException:执行时出现管道错误,看看RabbitMQ服务器日志,我看到了:

=INFO REPORT==== 29-Dec-2014::15:55:30 ===
accepting AMQP connection <0.644.0> (127.0.0.1:35299 -> 127.0.0.1:5671)

=ERROR REPORT==== 29-Dec-2014::15:55:30 ===
SSL: certify: ssl_handshake.erl:1343:Fatal error: handshake failure

根据我在互联网上看到的内容和此处,我已尝试将验证值更改为verify_none,但是,在执行此操作时,我得到以下内容:< / p>

=INFO REPORT==== 29-Dec-2014::14:51:13 ===
accepting AMQP connection <0.311.0> (127.0.0.1:35271 -> 127.0.0.1:5671)

=ERROR REPORT==== 29-Dec-2014::14:51:17 ===
closing AMQP connection <0.311.0> (127.0.0.1:35271 -> 127.0.0.1:5671):
{handshake_error,starting,0,
                 {amqp_error,access_refused,
                             "EXTERNAL login refused: no peer certificate",
                             'connection.start_ok'}}

根据SSL troubleshooting页面下给出的建议,我尝试执行与服务器的s_client连接,再次使用不同的结果,具体取决于 verify 的值。 如果验证设置为verify_peer,我会收到以下信息:

developer@developer-VirtualBox:~/rabbitmqcert$ openssl s_client -tls1_2 -connect localhost:5671 -cert ruleprocessing.public.pem -key ruleprocessing.private.pem -CAfile devcafiles/cacert.pem 
CONNECTED(00000003)
depth=1 CN = RabbitMQCA
verify return:1
depth=0 CN = rabbitmq, O = dev
verify return:1
139797055162016:error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure:s3_pkt.c:1260:SSL alert number 40
139797055162016:error:1409E0E5:SSL routines:SSL3_WRITE_BYTES:ssl handshake failure:s3_pkt.c:596:
---
Certificate chain
 0 s:/CN=rabbitmq/O=dev
   i:/CN=RabbitMQCA
 1 s:/CN=RabbitMQCA
   i:/CN=RabbitMQCA
---
Server certificate
-----BEGIN CERTIFICATE-----
<<OMMITED>>
-----END CERTIFICATE-----
subject=/CN=rabbitmq/O=dev
issuer=/CN=RabbitMQCA
---
Acceptable client certificate CA names
/CN=RabbitMQCA
---
SSL handshake has read 1646 bytes and written 2103 bytes
---
New, TLSv1/SSLv3, Cipher is AES256-SHA256
Server public key is 2048 bit
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
SSL-Session:
    Protocol  : TLSv1.2
    Cipher    : AES256-SHA256
    Session-ID: FC972B9A5D3EC359DC0467C8F02410E3AD66DA151C4411C0D5892115A439431A
    Session-ID-ctx: 
    Master-Key: E4FE793C71692852F6F3C4E9C5CB17774D8A50511338EF2E75691DC0DC2119F56611FC959C12429BBAFD46EC760ED713
    Key-Arg   : None
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    Start Time: 1419871438
    Timeout   : 7200 (sec)
    Verify return code: 0 (ok)
---

如您所见,握手错误在开始时发生,但似乎已恢复。

如果验证设置为verify_none,我会收到以下信息:

CONNECTED(00000003)
depth=1 CN = RabbitMQCA
verify return:1
depth=0 CN = rabbitmq, O = dev
verify return:1
---
Certificate chain
 0 s:/CN=rabbitmq/O=dev
   i:/CN=RabbitMQCA
 1 s:/CN=RabbitMQCA
   i:/CN=RabbitMQCA
---
Server certificate
-----BEGIN CERTIFICATE-----
<<OMMITED>>
-----END CERTIFICATE-----
subject=/CN=rabbitmq/O=dev
issuer=/CN=RabbitMQCA
---
No client certificate CA names sent
---
SSL handshake has read 1666 bytes and written 663 bytes
---
New, TLSv1/SSLv3, Cipher is AES256-SHA256
Server public key is 2048 bit
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
SSL-Session:
    Protocol  : TLSv1.2
    Cipher    : AES256-SHA256
    Session-ID: C4156551790BA116DC38A981728A71768D0B53AAEBEE969A4DA150746E5373FB
    Session-ID-ctx: 
    Master-Key: 3470DD0C0247B94EA784C3CEF94888C160205E9F06C14869B564A00AF5E4F7FAF5B4FC977E290B80DBCD140133F75AC0
    Key-Arg   : None
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    Start Time: 1419871570
    Timeout   : 7200 (sec)
    Verify return code: 0 (ok)
---

这次,在开始时不会发生握手错误。

作为旁注,因为我不太清楚&#34;清洁度&#34;我得到的VM,我实际上尝试创建一个新的VM(相同的Ubuntu版本),安装RabbitMQ(相同的版本),以几乎相同的方式配置它(唯一改变的是证书位置)并运行相同的客户端代码(修改证书路径)。最终结果是成功。不幸的是,我目前无法将此VM用作开发虚拟机。

TL; DR; 配置在Ubuntu VM上运行的RabbitMQ服务器以使用证书身份验证接受来自Java客户端的SSL连接后,所有连接尝试都会因握手失败而失败如果验证 = verify_peer,或者 EXTERNAL登录被拒绝:无对等证书,如果验证 = verify_none

1 个答案:

答案 0 :(得分:3)

问题与客户端证书的签名方式有关。它们是使用server_ca_extensions而不是使用client_ca_extensions签名的。