Mosquitto与TwinCAT 3 SSL证书认证连接时出现协议错误求助
问题
我是MQTT新手,希望在Windows环境下通过带SSL证书认证的MQTT连接Mosquitto与TwinCAT 3,但连接时Mosquitto提示protocol error。
我已通过OpenSSL生成SSL证书,使用的命令如下:
生成CA证书和密钥:
openssl req -x509 -newkey rsa:4096 -days 365 -keyout ca-key.pem -out ca-cert.pem -nodes
生成MQTT客户端密钥和CSR:
openssl req -newkey rsa:4096 -keyout client-key.pem -out client-req.pem -nodes
用CA签署CSR:
openssl x509 -req -in server-req.pem -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -out client-cert.pem
我已在Mosquitto程序文件夹中新建目录保存所有生成的证书和密钥,并修改Mosquitto.conf配置文件,让MQTT代理在本地8883端口启用SSL证书认证:
listener 8883 protocol mqtt require_certificate true cafile C:\Program Files\mosquitto\certs\ca-cert.pem keyfile C:\Program Files\mosquitto\certs\client-key.pem certfile C:\Program Files\mosquitto\certs\client-cert.pem
接下来,我在TwinCAT 3 PLC软件中通过以下代码设置发布客户端:
PROGRAM MAIN VAR fbMqttClient: FB_IotMqttClient; TopicToPublish : STRING(255) := 'Temperatures'; MessageToPublish : STRING(255); fbSendMessageIntervalTimer : TON := (PT:=T#1S); ai_RoomTemperature AT %I* : INT; END_VAR IF _TaskInfo[GETCURTASKINDEXEX()].FirstCycle THEN fbMqttClient.sHostName := '127.0.0.1'; fbMqttClient.nHostPort := 8883; fbMqttClient.sTopicPrefix := ''; fbMqttClient.sClientId := 'Publishing PLC'; fbMqTTClient.stTLS.sCert := 'C:\Program Files\mosquitto\certs\client-cert.pem'; fbMqTTClient.stTLS.sKeyFile := 'C:\Program Files\mosquitto\certs\client-key.pem'; fbMqTTClient.stTLS.sCA := 'C:\Program Files\mosquitto\certs\ca-cert.pem'; fbMqTTClient.stTLS.bNoServerCertCheck := TRUE; END_IF fbMqttClient.Execute(bConnect := TRUE); IF fbMqttClient.bConnected THEN fbSendMessageIntervalTimer(IN:=TRUE); IF fbSendMessageIntervalTimer.Q THEN fbSendMessageIntervalTimer(IN:=FALSE); MessageToPublish := CONCAT('Room temperature: ',REAL_TO_STRING(ai_RoomTemperature / 10.0)); fbMqttClient.Publish(sTopic:= TopicToPublish, pPayload:= ADR(MessageToPublish), nPayloadSize:= LEN2(ADR(MessageToPublish))+1, eQoS:= TcIotMqttQos.AtMostOnceDelivery, bRetain:= FALSE, bQueue:= FALSE); END_IF END_IF
在Mosquitto中执行mosquitto -c mosquitto.conf -v并启动TwinCAT程序后,Mosquitto出现以下错误:
1665110106: New connection from 127.0.0.1:63409 on port 8883. 1665110106: Client <unknown> disconnected due to protocol error.
我还测试了无证书认证的连接,此时Mosquitto与TwinCAT 3可正常连接,输出如下:
1665110793: New connection from 127.0.0.1:63889 on port 8883. 1665110793: New client connected from 127.0.0.1:63889 as Publishing PLC (p2, c1, k60). 1665110793: No will message specified. 1665110793: Sending CONNACK to Publishing PLC (0, 0) 1665110794: Received PUBLISH from Publishing PLC (d0, q0, r0, m0, 'Temperatures', ... (22 bytes)) 1665110795: Received PUBLISH from Publishing PLC (d0, q0, r0, m0, 'Temperatures', ... (22 bytes))
请问导致该协议错误的原因是什么,该如何排查解决?
原因分析
- 证书生成错误:签署客户端CSR时,命令中误用了
server-req.pem作为输入文件,但实际生成的客户端CSR是client-req.pem,导致生成的client-cert.pem无效。 - Mosquitto配置混淆:代理的
keyfile和certfile应使用服务器端专属证书和密钥,当前配置错误使用了客户端证书文件,破坏了TLS握手的身份验证逻辑。 - TLS参数逻辑冲突:TwinCAT中设置
bNoServerCertCheck := TRUE跳过服务端证书校验,但Mosquitto要求客户端提供有效证书,二者叠加引发握手协议错误。
解决步骤
1. 重新生成正确的证书链
步骤1:生成服务端证书和CSR
openssl req -newkey rsa:4096 -keyout server-key.pem -out server-req.pem -nodes
步骤2:用CA签署服务端CSR
openssl x509 -req -in server-req.pem -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem -days 365
步骤3:修正客户端证书签署命令
openssl x509 -req -in client-req.pem -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -out client-cert.pem -days 365
2. 修正Mosquitto配置文件
将mosquitto.conf中的服务端证书配置替换为正确的服务器证书:
listener 8883 protocol mqtt require_certificate true cafile C:\Program Files\mosquitto\certs\ca-cert.pem # 服务端专属密钥和证书 keyfile C:\Program Files\mosquitto\certs\server-key.pem certfile C:\Program Files\mosquitto\certs\server-cert.pem
修改后重启Mosquitto:
mosquitto -c mosquitto.conf -v
3. 调整TwinCAT的TLS参数
取消服务端证书校验跳过(服务端证书由自有CA签署,可正常校验):
IF _TaskInfo[GETCURTASKINDEXEX()].FirstCycle THEN // 其他配置保持不变 fbMqTTClient.stTLS.bNoServerCertCheck := FALSE; END_IF
4. 验证证书有效性
用OpenSSL命令检查证书链完整性:
openssl verify -CAfile ca-cert.pem server-cert.pem client-cert.pem
输出OK则证书有效,否则检查证书生成时的CN等参数是否匹配。
5. 排查TLS握手细节
开启Mosquitto调试日志查看详细错误:
mosquitto -c mosquitto.conf -v -d
用openssl s_client测试TLS连接:
openssl s_client -connect 127.0.0.1:8883 -cert client-cert.pem -key client-key.pem -CAfile ca-cert.pem
握手成功会显示SSL连接信息,失败则会给出具体错误提示。
内容的提问来源于stack exchange,提问作者NormanElledge
相关产品推荐
相关产品推荐

