添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement . We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account X.509 client auth: Username 'undefined' login failed for not_authorized despite verify_peer, peer_cert_as_username #2972 X.509 client auth: Username 'undefined' login failed for not_authorized despite verify_peer, peer_cert_as_username #2972 juwalter opened this issue Oct 12, 2019 · 7 comments

Description

When running emqx/emqx:v3.2.1 and using the following ENV settings:

    - EMQX_LISTENER__TCP__EXTERNAL__PEER_CERT_AS_USERNAME=cn
    - EMQX_LISTENER__SSL__EXTERNAL__VERIFY=verify_peer
    - EMQX_LISTENER__SSL__EXTERNAL__FAIL_IF_NO_PEER_CERT=true
    - EMQX_LISTENER__SSL__EXTERNAL__KEYFILE=etc/certs/server.key
    - EMQX_LISTENER__SSL__EXTERNAL__CERTFILE=etc/certs/server-cert.pem
    - EMQX_LISTENER__SSL__EXTERNAL__CACERTFILE=etc/certs/root-cacert.pem
    - EMQX_LOADED_PLUGINS="emqx_auth_redis,emqx_recon,emqx_retainer,emqx_management,emqx_dashboard"
    - EMQX_ALLOW_ANONYMOUS=false
    - EMQX_ACL_NOMATCH=deny
    - EMQX_LISTENER__TCP__EXTERNAL=1883
    - EMQX_AUTH__REDIS__SERVER=redis:6379
    - EMQX_AUTH__REDIS__PASSWORD_HASH=salt,sha256
    - EMQX_AUTH__REDIS__SUPER_CMD=HGET mqtt_user:%u is_superuser
    - EMQX_AUTH__REDIS__AUTH_CMD=HMGET mqtt_user:%u password salt
    - EMQX_AUTH__REDIS__ACL_CMD=HGETALL mqtt_acl:%u

I am not able to authenticate via the user in "CN" of the subject in the certificate. Instead, I see the following log output: (Username: 'undefined') login failed for not_authorized

emqx_1 | 2019-10-12 12:37:11.099 [debug] 192.168.128.1:35770 [Channel] RECV <<16,37,0,6,77,81,73,115,100,112,3,2,0,60,0,23,109,111,115,113, emqx_1 | 115,117,98,124,54,52,51,48,48,45,74,74,77,45,77,97,99,98,111>> emqx_1 | 2019-10-12 12:37:11.100 [debug] 192.168.128.1:35770 [Protocol] RECV CONNECT(Q0, R0, D0, ClientId=mosqsub| 64300-JJM-Macbo, ProtoName=MQIsdp, ProtoVsn=3, CleanStart=true, KeepAlive=60, Username=undefined, Password=undefined) emqx_1 | 2019-10-12 12:37:11.101 [warning] mosqsub| [email protected]:35770 [Protocol] Client mosqsub| 64300-JJM-Macbo (Username: 'undefined') login failed for not_authorized emqx_1 | 2019-10-12 12:37:11.103 [debug] mosqsub| [email protected]:35770 [Protocol] SEND CONNACK(Q0, R0, D0, AckFlags=0, ReasonCode=5) emqx_1 | 2019-10-12 12:37:11.106 [debug] mosqsub|[email protected]:35770 [Channel] Terminated for {shutdown,unauthorized_client}

Using mosquitto_sub like so:

mosquitto_sub -t sensors -h 127.0.0.1 -p 8883 -d --insecure \
        --cafile certs/root-cacert.pem  --cert certs/client-cert.pem \
        --key certs/client.key

Log from EMQX after starting up: (I have marked those relevant to the issue with '<------------')

emqx_1   | auth.redis.password_hash=salt,sha256
emqx_1   | node.max_ports=1048576
emqx_1   | listener.ssl.external.verify=verify_peer                   <------------
emqx_1   | auth.redis.server=redis:6379
emqx_1   | listener.tcp.external.acceptors=64
emqx_1   | auth.redis.super_cmd=HGET mqtt_user:%u is_superuser
emqx_1   | listener.ssl.external.certfile=etc/certs/server-cert.pem   <------------
emqx_1   | listener.ssl.external.fail_if_no_peer_cert=true            <------------
emqx_1   | auth.redis.acl_cmd=HGETALL mqtt_acl:%u
emqx_1   | allow_anonymous=false                                       <------------                                                           
emqx_1   | listener.ssl.external.acceptors=32
emqx_1   | listener.ssl.external.keyfile=etc/certs/server.key          <------------
emqx_1   | node.process_limit=2097152
emqx_1   | node.max_ets_tables=2097152
emqx_1   | listener.ws.external.acceptors=16
emqx_1   | listener.ssl.external.cacertfile=etc/certs/root-cacert.pem   <------------
emqx_1   | [email protected]
emqx_1   | auth.redis.auth_cmd=HMGET mqtt_user:%u password salt
emqx_1   | listener.tcp.external=1883
emqx_1   | listener.tcp.external.peer_cert_as_username=cn               <------------
emqx_1   | acl_nomatch=deny                                             <------------
emqx_1   | EMQX_LOADED_PLUGINS="emqx_auth_redis,emqx_recon,emqx_retainer,emqx_management,emqx_dashboard"
emqx_1   | emqx v3.2.3 is started successfully!
emqx_1   | ['2019-10-12T03:33:07Z']:emqx start

Creating the certificates

I followed this blog post in creating the certificates:

https://www.emqx.io/blog/45

When doing the "Two-way authentication test", I can see that the client does send the certificate and includes the "CN":

Server

openssl s_server -accept 2009 -key certs/server.key -cert certs/server-cert.pem -CAfile certs/root-cacert.pem -Verify 1
verify depth is 1, must return a certificate
Using auto DH parameters
Using default temp ECDH parameters
ACCEPT
depth=1 C = CN, ST = hangzhou, O = EMQ, CN = RootCA
verify return:1
depth=0 C = CN, ST = hangzhou, O = EMQ, CN = Client
verify return:1
-----BEGIN SSL SESSION PARAMETERS-----
-----END SSL SESSION PARAMETERS-----
Client certificate
-----BEGIN CERTIFICATE-----
-----END CERTIFICATE-----
subject=/C=CN/ST=hangzhou/O=EMQ/CN=Client
issuer=/C=CN/ST=hangzhou/O=EMQ/CN=RootCA
Shared ciphers:ECDHE-RSA-AES256-GCM-SHA384:...
CIPHER is ECDHE-RSA-AES256-GCM-SHA384
Secure Renegotiation IS supported

Client

openssl x509 -noout -subject -in certs/client-cert.pem
subject= /C=CN/ST=hangzhou/O=EMQ/CN=Client
-----------------------
openssl s_client -connect localhost:2009 -key certs/client.key -cert certs/client-cert.pem -CAfile certs/root-cacert.pem -showcerts
CONNECTED(00000005)
depth=1 C = CN, ST = hangzhou, O = EMQ, CN = RootCA
verify return:1
depth=0 C = CN, ST = hangzhou, O = EMQ, CN = Server
verify return:1
Certificate chain
 0 s:/C=CN/ST=hangzhou/O=EMQ/CN=Server
   i:/C=CN/ST=hangzhou/O=EMQ/CN=RootCA
-----BEGIN CERTIFICATE-----
-----END CERTIFICATE-----
Server certificate
subject=/C=CN/ST=hangzhou/O=EMQ/CN=Server
issuer=/C=CN/ST=hangzhou/O=EMQ/CN=RootCA
Acceptable client certificate CA names
/C=CN/ST=hangzhou/O=EMQ/CN=RootCA
Server Temp Key: ECDH, P-256, 256 bits
SSL handshake has read 3208 bytes and written 2257 bytes
New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES256-GCM-SHA384
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
    Protocol  : TLSv1.2
    Cipher    : ECDHE-RSA-AES256-GCM-SHA384
    Session-ID: DB9444AA28967332EBEEA98713B984481D464061DC9FD02F6A90CEBEBC63E522
    Session-ID-ctx:
    Master-Key: D2566198F7AA135EFC38DCC3EEB3638FB94C3FEFF647E0FFBB4BF2EB9ACD6E123207EF5F9F562303C865AC5F20045F74
    TLS session ticket lifetime hint: 7200 (seconds)
    TLS session ticket:

Summary

I would like to use the CN in the client certificate as username when connecting to EMQX. However, configuring peer_cert_as_username and verify_peer does not seem to have any effect.

References

Related issues #1966 and #1932

I have created a repo to more easily reproduce the the issue at:

https://github.com/juwalter/emqx-x509-issue

btw- using the instructions/example here http://www.steves-internet-guide.com/creating-and-using-client-certificates-with-mqtt-and-mosquitto/

I can confirm that it works with the very same certificates I used to connect to EMQX; the user is identified by the client (subject 'Client' from certificate) certificate: New client connected (p1, c1, k60, u'Client').

mosquitto -v -c /mosquitto/config/mosquitto.conf
1570886965: mosquitto version 1.6.7 starting
1570886965: Config loaded from /mosquitto/config/mosquitto.conf.
1570886965: Opening ipv4 listen socket on port 8883.
1570886965: Opening ipv6 listen socket on port 8883.
1570886965: Opening ipv4 listen socket on port 1883.
1570886965: Opening ipv6 listen socket on port 1883.
1570886975: New connection from 172.17.0.1 on port 8883.
1570886975: New client connected from 172.17.0.1 as mosqsub|
65264-JJM-Macbo (p1, c1, k60, u'Client').
1570886975: No will message specified.
1570886975: Sending CONNACK to mosqsub|65264-JJM-Macbo (0, 0)
1570886975: Received SUBSCRIBE from mosqsub|65264-JJM-Macbo
1570886975: 	sensors/# (QoS 0)
1570886975: mosqsub|65264-JJM-Macbo 0 sensors/#
1570886975: Sending SUBACK to mosqsub|65264-JJM-Macbo
1570887035: Received PINGREQ from mosqsub|65264-JJM-Macbo
1570887035: Sending PINGRESP to mosqsub|65264-JJM-Macbo

Config:

tail /mosquitto/config/mosquitto.conf
#ssl settings
cafile /certs/root-cacert.pem
keyfile /certs/server.key
certfile /certs/server-cert.pem
#client certifcate settings
require_certificate true
use_identity_as_username true

Command to connect:

 mosquitto_sub -t 'sensors/#' -h 127.0.0.1 -p 8883 -d --insecure \
   --cafile certs/root-cacert.pem  --cert certs/client-cert.pem \
    --key certs/client.key

Note: I still won't rule out a wrong or incomplete configuration of the certificates, though, since from what I understand, the SSL subsystem from Erlang is very picky?

Just realized, there are two settings for peer_cert_as_username

  • listener.tcp.external.peer_cert_as_username
  • listener.ssl.external.peer_cert_as_username
  • https://github.com/emqx/emqx/blob/master/etc/emqx.conf#L1262

    I have updated my config, and it is now also using listener.ssl.external.peer_cert_as_username=cn but it does not make a difference.

    Looking at the code, where it is evaluated:

    emqx/src/emqx_channel.erl Line 181 f3f828d

    Hi @tigercl - thanks for your reply.

    I did everything according to the blog post you mentioned (blog 45) and I did try with your suggestions (verify = verify_peer and fail_if_no_peer_cert = true). Pls see the demo project to reproduce the issue I have created here: https://github.com/juwalter/emqx-x509-issue/blob/master/docker-compose.yml#L25

    I also can confirm that the client did send the certificate to the server:

    a) two-way authentication test (see my original post)
    b) test with Mosquitto (see my first comment)

    Do you have any further suggestions or ideas that I could pursue?

    Thanks! Jürgen

    I am having the same problem. I am trying to use the feature to link and lock a certificate (CN=Device SerialNr.) to a topic.
    Quadruple-checked my config and also tried to set listener.ssl.external.peer_cert_as_username=crt and listener.ssl.external.peer_cert_as_username=dn but I am always getting Username=undefined.