X.509 client auth: Username 'undefined' login failed for not_authorized despite verify_peer, peer_cert_as_username
- 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
.