MQTT研究之EMQ:【SSL雙向驗證】

EMQ是當前MQTT中,用於物聯網領域中比較出色的一個broker,今天我這裏要記錄和分享的是關於SSL安全通訊的配置和注意細節。html

 

環境:node

1. 單臺Linux CentOS7.2系統,安裝一個EMQTTD的實例broker。windows

2. emq的版本2.3.11。安全

3. 客戶端分爲mosquitto_pub,以及MQTT.fx 1.7.1的subscriber。app

4. 證書是經過openssl(version:1.0.2k-fips)生成的,rootCA是自簽名的,subscriber和publisher的證書是經過rootCA簽署的。ide

 

一、CA根證書的生成工具

[root@ws3 certs]# openssl req -x509 -new -days 3650 -keyout ca.key -out rootCA.crt -nodes
Generating a 2048 bit RSA private key
.....................+++
.........................................................................................................................+++
writing new private key to 'ca.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:CN  
State or Province Name (full name) []:Hubei
Locality Name (eg, city) [Default City]:Wuhan
Organization Name (eg, company) [Default Company Ltd]:abcdefg
Organizational Unit Name (eg, section) []:Tkcloud
Common Name (eg, your name or your server's hostname) []:10.95.197.3
Email Address []:

 

二、爲server端生成證書測試

a. 生成私有祕鑰ui

[root@ws3 certs]# openssl genrsa -out server.key 2048
Generating RSA private key, 2048 bit long modulus
...................................................+++
............+++
e is 65537 (0x10001)

 

b. 生成證書請求csr文件this

[root@ws3 certs]# openssl req -new -key server.key -out server.csr
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:Hubei
Locality Name (eg, city) [Default City]:Wuhan
Organization Name (eg, company) [Default Company Ltd]:abcdefg
Organizational Unit Name (eg, section) []:Cloud
Common Name (eg, your name or your server's hostname) []:10.95.197.3
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

 

c. 生成證書

[root@ws3 certs]# openssl ca -in server.csr -out server.crt -cert rootCA.crt -keyfile ca.key -days 3650
Using configuration from /etc/pki/tls/openssl.cnf
/etc/pki/CA/index.txt: No such file or directory
unable to open '/etc/pki/CA/index.txt'
140188069304208:error:02001002:system library:fopen:No such file or directory:bss_file.c:402:fopen('/etc/pki/CA/index.txt','r')
140188069304208:error:20074002:BIO routines:FILE_CTRL:system lib:bss_file.c:404:

錯誤分析:
缺少/etc/pki/CA/index.txt,對應的建立一個空文件便可

再次執行證書生成過程:

[root@ws3 certs]# openssl ca -in server.csr -out server.crt -cert rootCA.crt -keyfile ca.key -days 3650           
Using configuration from /etc/pki/tls/openssl.cnf
/etc/pki/CA/serial: No such file or directory
error while loading serial number
140539902367632:error:02001002:system library:fopen:No such file or directory:bss_file.c:402:fopen('/etc/pki/CA/serial','r')
140539902367632:error:20074002:BIO routines:FILE_CTRL:system lib:bss_file.c:404:

錯誤分析:
缺少/etc/pki/CA/serial文件,對應的建立這個文件
再次執行上述生成指令:

[root@ws3 certs]# openssl ca -in server.csr -out server.crt -cert rootCA.crt -keyfile ca.key -days 3650
Using configuration from /etc/pki/tls/openssl.cnf
unable to load number from /etc/pki/CA/serial
error while loading serial number
140553210034064:error:0D066096:asn1 encoding routines:a2i_ASN1_INTEGER:short line:f_int.c:210:

錯誤分析:
缺少序號數據,是沒有序號數據。寫入1,保存後,繼續執行上述過程

[root@ws3 certs]# openssl ca -in server.csr -out server.crt -cert rootCA.crt -keyfile ca.key -days 3650
Using configuration from /etc/pki/tls/openssl.cnf
unable to load number from /etc/pki/CA/serial
error while loading serial number
139880943351696:error:0D066096:asn1 encoding routines:a2i_ASN1_INTEGER:short line:f_int.c:210:

錯誤分析:
寫的數據格式不對,須要寫入兩位的01格式,保存後繼續運行。

[root@ws3 certs]# openssl ca -in server.csr -out server.crt -cert rootCA.crt -keyfile ca.key -days 3650
Using configuration from /etc/pki/tls/openssl.cnf
Check that the request matches the signature
Signature ok
Certificate Details:
        Serial Number: 1 (0x1)
        Validity
            Not Before: Jan 17 14:38:42 2019 GMT
            Not After : Jan 14 14:38:42 2029 GMT
        Subject:
            countryName               = CN
            stateOrProvinceName       = Hubei
            organizationName          = abcdefg
            organizationalUnitName    = Cloud
            commonName                = 10.95.197.3
        X509v3 extensions:
            X509v3 Basic Constraints: 
                CA:FALSE
            Netscape Comment: 
                OpenSSL Generated Certificate
            X509v3 Subject Key Identifier: 
                90:F2:F6:57:31:DB:1A:81:B7:11:08:12:46:A0:FE:DB:6F:84:A9:DE
            X509v3 Authority Key Identifier: 
                keyid:DF:2F:DC:D6:75:2A:06:C0:D0:39:6C:32:11:A8:60:72:F4:9B:EB:DD

Certificate is to be certified until Jan 14 14:38:42 2029 GMT (3650 days)
Sign the certificate? [y/n]:y


1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated

CA這個信息爲FALSE,代表這個證書不是根證書

上面的rootCA.crt是根證書,看看內容:

[root@ws3 certs]# openssl x509 -text -in rootCA.crt -noout   
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            db:61:ba:05:39:42:54:21
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=CN, ST=Hubei, L=Wuhan, O=abcdefg, OU=Tkcloud, CN=10.95.197.3
        Validity
            Not Before: Jan 17 15:20:50 2019 GMT
            Not After : Dec 24 15:20:50 2118 GMT
        Subject: C=CN, ST=Hubei, L=Wuhan, O=abcdefg, OU=Tkcloud, CN=10.95.197.3
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:95:b4:50:75:5b:c6:23:b4:67:1c:5f:89:25:b8:
                    bf:8a:9b:e1:fa:95:81:81:87:71:2b:6e:16:b9:07:
                    a2:1c:67:76:35:da:fb:5b:25:6b:db:bd:29:cd:55:
                    98:ca:95:3e:2f:bb:c3:b5:61:4d:c9:d6:9c:1b:b9:
                    06:59:24:e8:ed:5a:d9:ca:84:07:4e:7d:e6:42:8f:
                    7e:98:25:48:17:9c:18:d4:ff:26:c4:aa:dc:dd:de:
                    91:78:33:e2:9c:3d:95:56:4d:d1:5a:78:ea:b8:49:
                    38:1e:b8:89:a3:6f:79:ba:b2:97:02:81:5c:8b:0b:
                    d3:45:be:a1:49:e6:64:26:59:cf:86:18:14:3a:31:
                    f0:e1:c8:04:52:1e:cf:fb:4a:ee:5a:a9:7d:bc:63:
                    d2:fe:2c:f5:8f:a4:b2:cc:52:92:d2:9d:a0:d2:2e:
                    4e:4f:e7:77:6c:0d:81:59:42:13:b6:7c:19:45:f6:
                    e9:c6:33:5e:21:ea:01:02:61:2d:53:e2:f2:bf:06:
                    59:63:7e:37:cf:bd:2a:44:63:77:c1:8f:c5:56:9e:
                    35:f8:26:17:08:79:75:c3:05:2f:b4:fc:d2:95:96:
                    cb:0c:dd:6f:ef:9f:5d:57:48:4e:78:2b:75:2e:3a:
                    37:8e:c9:95:f0:7c:92:80:a3:ac:f7:66:9d:16:59:
                    e7:f9
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Subject Key Identifier: 
                AB:2E:65:BE:15:CB:A1:29:A4:09:97:A8:CB:39:2A:3F:ED:4C:1E:16
            X509v3 Authority Key Identifier: 
                keyid:AB:2E:65:BE:15:CB:A1:29:A4:09:97:A8:CB:39:2A:3F:ED:4C:1E:16

            X509v3 Basic Constraints: 
                CA:TRUE
    Signature Algorithm: sha256WithRSAEncryption
         4c:35:ad:41:4f:9d:e6:c3:f2:87:08:50:70:4f:81:09:da:1c:
         c4:d7:25:60:0f:1a:d6:2b:e8:8e:9d:45:6e:47:13:ee:b0:c2:
         21:96:2e:e2:eb:2e:c0:a7:60:ba:00:dc:b6:94:45:f9:7d:ff:
         97:dc:dc:92:d3:aa:85:2a:fe:f4:91:c7:0e:f8:2e:de:2d:28:
         a0:a1:f5:74:f1:cc:8f:2f:00:fe:0c:35:6d:de:00:ff:46:8c:
         22:21:53:22:ea:2b:b1:7d:ac:e4:b4:c0:e7:91:95:40:96:da:
         93:48:57:91:88:0a:6d:3d:a5:de:65:9b:be:72:ef:d0:f4:2a:
         a0:db:47:6e:6c:bf:f6:fb:a7:3f:1c:4b:bd:c6:6c:9f:62:3b:
         d3:d3:b3:7f:ce:b8:83:86:20:c1:28:8e:42:c2:60:d1:26:ee:
         33:27:e2:78:a7:0c:26:3a:b9:94:01:c6:11:19:56:77:76:e7:
         ed:06:fc:76:d9:7e:06:f8:a3:15:8a:a2:89:33:b5:e0:0e:9d:
         4d:3a:b6:15:33:40:0d:26:ac:67:92:0b:96:17:13:66:93:c8:
         0d:ea:ed:68:e9:ff:4a:3e:e5:27:53:71:e2:53:82:83:f1:68:
         01:d9:6b:5b:51:bf:84:7f:ad:0d:2f:98:d6:fb:04:a4:e5:78:
         1c:82:94:de

 

證書生成完畢後,查看上面建立的index.txt以及serial文件:

[root@ws3 certs]# vi /etc/pki/CA/index.txt
V       290114143842Z           01      unknown /C=CN/ST=Hubei/O=abcdefg/OU=Cloud/CN=10.95.197.3
[root@ws3 certs]# vi /etc/pki/CA/serial
02

注意:起初index.txt是空的,證書建立成功後,寫入了一條記錄。serial文件,起初是01,然而,如今變成了02.

 

3. 爲客戶端生成證書

這裏,省略生成私鑰,以及證書請求的過程,重點關注基於根證書rootCA.crt生成證書的過程。

[root@ws3 certs]# openssl ca -in client.csr -out client.crt -cert rootCA.crt -keyfile ca.key 
Using configuration from /etc/pki/tls/openssl.cnf
Check that the request matches the signature
Signature ok
Certificate Details:
        Serial Number: 2 (0x2)
        Validity
            Not Before: Jan 17 14:56:37 2019 GMT
            Not After : Jan 17 14:56:37 2020 GMT
        Subject:
            countryName               = CN
            stateOrProvinceName       = Hubei
            organizationName          = abcdefg
            organizationalUnitName    = cloud
            commonName                = client
        X509v3 extensions:
            X509v3 Basic Constraints: 
                CA:FALSE
            Netscape Comment: 
                OpenSSL Generated Certificate
            X509v3 Subject Key Identifier: 
                D7:A0:13:02:40:47:1F:E1:89:71:EA:60:31:57:3A:A5:50:7D:5B:43
            X509v3 Authority Key Identifier: 
                keyid:DF:2F:DC:D6:75:2A:06:C0:D0:39:6C:32:11:A8:60:72:F4:9B:EB:DD

Certificate is to be certified until Jan 17 14:56:37 2020 GMT (365 days)
Sign the certificate? [y/n]:y


1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated

客戶證書只有1年(不加參數-days的話,默認是1年),而服務端證書時候10年的有效期

 

4. 驗證雙向SSL的通訊過程。

1). 配置emqtt

## Path to a file containing the user certificate.
##
## See: http://erlang.org/doc/man/ssl.html
##
## Value: File
#listener.ssl.external.certfile = /etc/emqttd/certs/cert.pem
listener.ssl.external.certfile = /opt/certs/server.crt

## Path to the file containing PEM-encoded CA certificates. The CA certificates
## are used during server authentication and when building the client certificate chain.
##
## Value: File
## listener.ssl.external.cacertfile = /etc/emqttd/certs/cacert.pem
listener.ssl.external.cacertfile = /opt/certs/rootCA.crt

## The Ephemeral Diffie-Helman key exchange is a very effective way of
## ensuring Forward Secrecy by exchanging a set of keys that never hit
## the wire. Since the DH key is effectively signed by the private key,
## it needs to be at least as strong as the private key. In addition,
## the default DH groups that most of the OpenSSL installations have
## are only a handful (since they are distributed with the OpenSSL
## package that has been built for the operating system it’s running on)
## and hence predictable (not to mention, 1024 bits only).
## In order to escape this situation, first we need to generate a fresh,
## strong DH group, store it in a file and then use the option above,
## to force our SSL application to use the new DH group. Fortunately,
## OpenSSL provides us with a tool to do that. Simply run:
## openssl dhparam -out dh-params.pem 2048
##
## Value: File
## listener.ssl.external.dhfile = /etc/emqttd/certs/dh-params.pem

## A server only does x509-path validation in mode verify_peer,
## as it then sends a certificate request to the client (this
## message is not sent if the verify option is verify_none).
## You can then also want to specify option fail_if_no_peer_cert.
## More information at: http://erlang.org/doc/man/ssl.html
##
## Value: verify_peer | verify_none
listener.ssl.external.verify = verify_peer

## Used together with {verify, verify_peer} by an SSL server. If set to true,
## the server fails if the client does not have a certificate to send, that is,
## sends an empty certificate.
##
## Value: true | false listener.ssl.external.fail_if_no_peer_cert = true

上述幾個紅色的部分,是涉及SSL通訊要用到的。單雙向驗證的核心參數是listener.ssl.external.verify = verify_peer,這裏是雙向驗證,即服務端要向客戶端發起身份驗證工做。verify_none表示服務端不對客戶端進行身份驗證

 

2). 這裏消費者客戶端使用的是MQTT.fx客戶端工具(1.7.1),跑在windows機器上。

a. 按照下面的config.jpg圖片顯示內容,配置好相關信息。

emqtt配置了用戶身份認證,是經過用戶名和密碼作的。必須輸入上述參數

上圖中配置的證書相關的參數對應的文件,就是前面生成的證書相關文件,copy到了MQTT.fx所在的windows機器上了


b. 按照圖connection.jpg點擊connect便可,如圖所示表示鏈接成功。


c. 按照圖片subscribe.jpg所示,進行訂閱。

 

3). 消息生產者跑在Linux機器上,經過mosquitto_pub實現。

[root@ws3 certs]# mosquitto_pub -h 10.95.197.3 -t taikang/rulee --cafile /opt/certs/rootCA.crt --cert /opt/certs/client.crt --key /opt/certs/client.key -u water -P water -m "hellooooo my iot platform"

此時,MQTT.fx客戶端上收到了剛纔發送的數據,結果以下圖.

 

4). 這裏,基於上面listener.ssl.external.verify = verify_peer (broker要驗證client的身份)作些方向測試驗證,主要驗證是否是雙向驗證邏輯

a. MQTT.fx上,將證書中client.key換成其餘的key,和client.crt不配對的,看可否創建鏈接。效果如圖下圖. 並且,配置中根證書,客戶證書,客戶私鑰,這三個任何一個配置不匹配,會出現不一樣的錯誤信息,自行嘗試驗證。

 

b. Mosquitto_pub端,選擇將cert的參數選成另一個證書,和上述的client.key不匹配便可,錯誤以下:

[root@ws3 certs]# mosquitto_pub -h 10.95.197.3 -t taikang/rulee --cafile /opt/certs/rootCA.crt --cert /etc/emqttd/certs/client-cert.pem --key /opt/certs/client.key -u water -P water -m "hellooooo5" -d                 
Error: Unable to load client key file "/opt/certs/client.key".
OpenSSL Error: error:0B080074:x509 certificate routines:X509_check_private_key:key values mismatch
Unable to connect (A TLS error occurred.).

從上面a和b兩邊的測試驗證,說明自行生成的客戶端和服務端證書,在emqtt配置成雙向驗證的狀況下,工做是符合設定的業務邏輯的。

 

下一篇博文,將從wireshark抓包的角度分析SSL通訊模式下,單向驗證和雙向驗證,在SSL/TLS消息流上的差別。

相關文章
相關標籤/搜索