要想实现moquitto 服务器证书加密通信,首先要自己生成client 和server的证书,证书生成又需要签名证书,一般签名证书是第三方机构来提供,但我们自己也可以实现签名证书生成,下面是具体签名证书的生成步骤:
1.1 生成自己CA签发证书(该证书用于给server和client 生成证书)
1.1.1 生成 rootca 证书命令
openssl genrsa -out rootCA.key 2048
1.1.2 根据key 生成csr 文件(发给ca 机构,生成crt证书)
openssl req -new -out rootCA.csr -key rootCA.key
注意:这里会提示 输入国家,省份,城市,公司,等等信息,可以自定义填写,但要记住你填了什么,因为后面签发client, server证书的时候也需要;
1.1.3 CA机构根据CSR(证书签发请求)(自己给自己)签发证书
openssl x509 -req -sha1 -in rootCA.csr -out rootCA.crt -signkey rootCA.key -days 3650
到此签发证书已经生成,会在目录一下看到有rootCA.csr rootCA.crt rootCA.key 三个文件
rootCA.crt 就是后面要用的签发证书;
1.2 使用上面制作的签发跟证书为server 和client 生成相应的私钥和证书
1.2.1 先生成server key, 在用server key 生成server csr(签名请求),使用root ca ( 证 书签发机构CA)和server csr 生成server.crt 证书
首先自己生成server的私钥,
openssl genrsa -out server.key 2048
生成签名请求 server.csr(用于生成证书)
openssl req -new -out server.csr -key server.key
使用私钥,根证书,生成证书
openssl x509 -req -in server.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out server.crt -days 3650
到此server.key 和server.crt 已生成; client 证书通过以上三条命令生成
注:Client 一样 (common name server 和client 应该都是server ip) CA 的common name 应该设置为0.0.0.0
1.2.2 证书校验命令
openssl verify -CAfile ca/rootCA.crt client/client.crt (校验证书是否可以使用)
cp /etc/mosquito/mosquito.conf.example /etc/mosquito/mosquito.conf.example
修改配置文件权限,添加mosquitto 权限
groupadd mosquitto
useradd -g mosquitto mosquitto
chown -R mosquitto:mosquitto /etc/mosquitto/
配置允许匿名访问。
allow_anonymous true
require_certificate true
use_identity_as_username true //单双向验证配置, false 单项(默认),true 双向
cafile (需要填写绝对路径)
certfile (需要填写绝对路径)
修改完配置,重启mosquitto server 即可;
mosquitto_sub -h 10.30.11.47 -p 8884 -t "mqtt/server/topic" --cafile ./ca/ca.crt &
单项验证
mosquitto_sub -h 10.30.11.47 -p 8883 -t "mqtt/server/topic" --cafile ./ca/ca.crt --cert ./client/client.pem --key ./client/client.key &
双向验证
在启动订阅端的时候,加上“--insecure”参数, 启动的时候将不再校验common name;
#include
#include
#include
#include "mosquitto.h"
//server ip
#define HOST "xx.xx.xx.xx"
#define PORT 8883
#define KEEP_ALIVE 60
#define MSG_MAX_SIZE 512
static int running = 1;
void my_connect_callback(struct mosquitto* mosq, void* obj, int rc)
{
printf("Call the function:on_connect\n");
if (rc)
{
printf("on_connect error!\n");
exit(1);
}
else
{
for (int i = 0; i < 10; i++)
{
char topic[1024] = { 0 };
snprintf(topic, sizeof(topic), "HELLOMQTT%d", i); //连接成功后初始化所有的topic
if (mosquitto_subscribe(mosq, NULL, topic, 2))
{
printf("Set the topic error!\n");
exit(1);
}
}
}
}
void my_disconnect_callback(struct mosquitto* mosq, void* obj, int rc)
{
printf("Call the function: my_disconnect_callback\n");
running = 0;
}
//初始化topic的时候,会调用这个回调
void my_subscribe_callback(struct mosquitto* mosq, void* obj, int mid, int qos_count, const int* granted_qos)
{
printf("Call the function: on_subscribe\n");
}
//topic 订阅到之后,回调处理
void my_message_callback(struct mosquitto* mosq, void* obj, const struct mosquitto_message* msg)
{
printf("Call the function: on_message\n");
printf("Recieve a message of %s: %s\n.", (char*)msg->topic, (char*)msg->payload);
if (0 == strcmp((const char*)msg->payload, "quit")) {
mosquitto_disconnect(mosq);
}
}
//初始化设置cert 和 设置不校验common name (--insecure)
int init_config(struct mosquitto* mosq)
{
int rc;
const char* firstMessage = "himqtt";
if (mosquitto_will_set(mosq, "HELLOMQTT",
strlen(firstMessage), firstMessage, 0,
true )) {
printf("Error: Problem setting will.\n");
mosquitto_lib_cleanup();
return 1;
}
{
rc = mosquitto_tls_set(mosq,"Y:/\mosquitto/\ca/\\rootCA.crt",
"Y:/\mosquitto/\ca", "Y:/\mosquitto/\client/\client.crt",
"Y:/\mosquitto/\client/\client.key", NULL);
if (rc) {
if (rc == MOSQ_ERR_INVAL) {
printf("Error: Problem setting TLS options: File not found.\n");
}
else
{
printf("Error: Problem setting TLS options: %s.\n",
mosquitto_strerror(rc));
}
mosquitto_lib_cleanup();
return 1;
}
}
//该函数是设置不校验证书的common name 也就是CN
if (mosquitto_tls_insecure_set(mosq, true)) {
printf("Error: Problem setting TLS insecure option.\n");
mosquitto_lib_cleanup();
return 1;
}
}
int main(int argc, char** argv)
{
int ret;
struct mosquitto* mosq;
ret = mosquitto_lib_init();
mosq = mosquitto_new("sub_test", true, NULL);
if (mosq == NULL)
{
printf("New sub_test error!\n");
mosquitto_lib_cleanup();
return -1;
}
init_config(mosq);
mosquitto_connect_callback_set(mosq, my_connect_callback);
mosquitto_disconnect_callback_set(mosq, my_disconnect_callback);
mosquitto_subscribe_callback_set(mosq, my_subscribe_callback);
mosquitto_message_callback_set(mosq, my_message_callback);
ret = mosquitto_connect(mosq, HOST, PORT, KEEP_ALIVE);
if (ret)
{
printf("Connect server error!\n");
mosquitto_destroy(mosq);
mosquitto_lib_cleanup();
return -1;
}
printf("Start!\n");
while (running)
{
mosquitto_loop(mosq, -1, 1);
//mosquitto_loop_start(mosq);
}
mosquitto_destroy(mosq);
mosquitto_lib_cleanup();
printf("End!\n");
return 0;
}
注意:mosquitto_tls_set 证书配置要写对
mosquitto_tls_insecure_set(mosq, true)
要设置不校验CN 不然可能会出现连接mosquitto server的失败
至此mosqutto server的证书双向校验配置结束;虽然写的很简陋,主要是本人配置过程中遇到的一些难点,记录下来;