websocket 之 SSL连接相关

MQTT and Websockets

paho.mqtt.c

ssl_opts.CApath = opts.capath; //指向一个包含PEM格式的CA证书的目录。
ssl_opts.keyStore = opts.cert; //客户机的公共证书链。它还可以包括客户机的私钥。
ssl_opts.trustStore = opts.cafile; //客户端信任的公共数字证书。
ssl_opts.privateKey = opts.key; //客户机私钥的PEM格式的文件
ssl_opts.privateKeyPassword = opts.keypass; //客户端私钥的密码(如果加密)
/** samples/paho_c_sub.c **/
if (opts.connection && (strncmp(opts.connection, "ssl://", 6) == 0 ||
			strncmp(opts.connection, "wss://", 6) == 0))
	{
		if (opts.insecure)
			ssl_opts.verify = 0;
		ssl_opts.CApath = opts.capath;
		ssl_opts.keyStore = opts.cert;
		ssl_opts.trustStore = opts.cafile;
		ssl_opts.privateKey = opts.key;
		ssl_opts.privateKeyPassword = opts.keypass;
		ssl_opts.enabledCipherSuites = opts.ciphers; //密码列表格式
		conn_opts.ssl = &ssl_opts;
	}

libwebsockets

Server

struct lws_context_creation_info info;
	info.ssl_ca_filepath=""; /*CA根证书*/
	info.ssl_cert_filepath=""; /*服务器公钥证书 */
	info.ssl_private_key_filepath=""; /*服务器的私钥*/
	info.ssl_cipher_list = "ECDHE-ECDSA-AES256-GCM-SHA384:"
			       "ECDHE-RSA-AES256-GCM-SHA384:"
			       "DHE-RSA-AES256-GCM-SHA384:"
			       "ECDHE-RSA-AES256-SHA384:"
			       "HIGH:!aNULL:!eNULL:!EXPORT:"
			       "!DES:!MD5:!PSK:!RC4:!HMAC_SHA1:"
			       "!SHA1:!DHE-RSA-AES128-GCM-SHA256:"
			       "!DHE-RSA-AES128-SHA256:"
			       "!AES128-GCM-SHA256:"
			       "!AES128-SHA256:"
			       "!DHE-RSA-AES256-SHA256:"
			       "!AES256-GCM-SHA384:"
			       "!AES256-SHA256";
case LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION:
	{
		X509 *cert;

		if (!len || (SSL_get_verify_result((SSL*) in) != X509_V_OK))
		{
			int err = X509_STORE_CTX_get_error((X509_STORE_CTX*) user);
			int depth = X509_STORE_CTX_get_error_depth((X509_STORE_CTX*) user);
			const char* msg = X509_verify_cert_error_string(err);
			log_d(": SSL error: %s (%d), depth: %d\n", msg, err, depth);
			return 1;
		}

Client

struct lws_context_creation_info info;
struct lws_context *context = NULL;
struct lws_user_client user;

memset(&user, 0, sizeof(user));
memset(&info, 0, sizeof info);

info.port = CONTEXT_PORT_NO_LISTEN;
info.gid = -1;
info.uid = -1;
info.user = &user;
info.protocols = protocols;

nlogd("use ssl\n");
//info.options |= LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT;
//info.options |= LWS_SERVER_OPTION_DISABLE_OS_CA_CERTS;
info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;

if (access("./ssl_key/ca.crt", F_OK) != 0)
	nloge("ca crt not exists\n");

const char *ssl_ca_filepath = "./ssl_key/ca.crt";
const char *ssl_cert_filepath = "./ssl_key/client.crt";
const char *ssl_private_key_filepath = "./ssl_key/client_rsa_private.pem";

info.ssl_ca_filepath = ssl_ca_filepath;
info.ssl_cert_filepath = ssl_cert_filepath;
info.ssl_private_key_filepath = ssl_private_key_filepath;
	
struct lws_client_connect_info i;
memset(&i, 0, sizeof(i));

i.path = "/aa";
i.address = "192.168.0.81";
i.port = 2000;
i.context = context;
i.host = "SERVER"; //注意这里,必须写成服务器证书里面的CN=
i.origin = "CA";
i.ietf_version_or_minus_one = -1;
i.protocol = protoname;
i.ssl_connection = 1;

// 下面的调用触发LWS_CALLBACK_PROTOCOL_INIT事件
wsi = lws_client_connect_via_info(&i);
....

关于QT

  connect(socket, SIGNAL(connected()), this, SLOT(onConnected()));
  //sslErrors 一定要设置
  connect(socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(onSslErrors(QList<QSslError>)));

    /*识别服务器证书是否合法*/
#if 0
    QList<QSslCertificate> cacert = QSslCertificate::fromPath("G:\\openssl-key\\cacert.crt", QSsl::Pem);
    //QList<QSslCertificate> cacert = QSslCertificate::fromPath("G:\\openssl-key\\single.server.crt", QSsl::Pem); //err

    QFile certFile(QString("G:\\openssl-key\\client.crt"));
    certFile.open(QIODevice::ReadOnly);
    QFile keyFile(QString("G:\\openssl-key\\client.key.pem"));
    keyFile.open(QIODevice::ReadOnly);
    QSslCertificate certs = QSslCertificate(certFile.readAll(), QSsl::Pem);
    QSslKey key= QSslKey(keyFile.readAll(), QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey);

    //The certificate is self-signed, and untrusted
    QSslConfiguration config;
    config.setCaCertificates(cacert);
    config.setLocalCertificate(certs);
    config.setPrivateKey(key);
    //config.setPeerVerifyMode(QSslSocket::VerifyNone);
    config.setProtocol(QSsl::TlsV1SslV3);
#else
    //The host name did not match any of the valid hosts for this certificate
    //openssl req -newkey rsa:2048 -nodes -keyout single.server.key.pem -x509 -days 365 -out single.server.crt -subj "/C=CN/ST=GD/L=SZ/O=hh/OU=dev/CN=192.168.2.130/emailAddress=aa@aa.com"
    QList<QSslCertificate> cacert = QSslCertificate::fromPath("G:\\openssl-key\\single.crt", QSsl::Pem);
    QSslConfiguration config;
    config.setCaCertificates(cacert);
    config.setProtocol(QSsl::TlsV1SslV3);
#endif

QT运行SSL需要 libeay32.dll和ssleay32.dll:
C:\Qt\Qt5.8.0\Tools\QtCreator\bin下的 libeay32.dll 和 ssleay32.dll 库复制到C:\Qt\Qt5.8.0\5.8\msvc2015_64\bin下。

单向认证:只需要验证SSL服务器身份,不需要验证SSL客户端身份。
双向认证:要求服务器和客户端双方都有证书,客户端需要校验服务端,服务端也需要校验客户端。

openssl生成证书

生成 RSA 私钥和自签名证书

#生成私钥与证书
openssl req -newkey rsa:2048 -nodes -keyout rsa_private.pem -x509 -days 365 -out cert.crt -subj "/C=CN/ST=GD/L=SZ/O=hh/OU=dev/CN=192.168.2.130/emailAddress=aa@aa.com"
#生成私钥
openssl genrsa -out privkey.pem 2048
#生成证书(含公钥)-已有key
openssl req -new -x509 -key privkey.pem -out cacert.crt -days 3650

这样便可以做单向认证,自己使用 privkey.pem 提供 cacert.crt 给其他人使用

#查看证书信息
openssl req -noout -text -in cacert.crt

#生成根证书私钥( cakey.pem 文件)                                                                                                   
openssl genrsa -out cakey.pem 2048                                                
#生成根证书签发申请文件( ca.csr 文件)                                                                                           
openssl req -new -key cakey.pem -out ca.csr -subj  "/C=CN/ST=GD/L=SZ/O=hh/OU=dev/CN=192.168.2.130/emailAddress=aa@aa.com"
#自签发根证书(cer文件) ,依据 ca.csr 和 cakey.pem 生成 cacert.pem                                
openssl x509 -req -days 365 -sha1 -extensions v3_ca -signkey cakey.pem -in ca.csr -out  cacert.pem
######################################################
#服务端私钥和证书
openssl genrsa -out server.key.pem 2048
openssl req -new -key server.key.pem -out server.csr -subj "/C=CN/ST=myprovince/L=mycity/O=myorganization/OU=mygroup/CN=myServer"
#使用根证书签发服务端证书 server.cert.pem
openssl x509 -req -days 365 -sha1 -extensions v3_req -CA cacert.pem -CAkey cakey.pem -CAserial ca.srl -CAcreateserial -in server.csr -out server.cert.pem
#使用CA证书验证server端证书,查看server.cert.pem,得到颁发者为192.168.2.130                                                                                              
openssl verify -CAfile cacert.pem  server.cert.pem
######################################################
#客户端私钥和证书 client.key.pem                                                                                                           
openssl genrsa  -out client.key.pem 2048                                                                                                         
openssl req -new -key client.key.pem -out client.csr -subj "/C=CN/ST=myprovince/L=mycity/O=myorganization/OU=mygroup/CN=myClient"
#使用根证书签发客户端证书 依据 cacert.pem + cakey.pem -> client.cert.pem                                                                                                 
openssl x509 -req -days 365 -sha1 -extensions v3_req -CA  cacert.pem -CAkey cakey.pem  -CAserial ca.srl -in client.csr -out client.cert.pem
#使用CA证书验证客户端证书                                                                                                  
openssl verify -CAfile cacert.pem  client.cert.pem  

cakey.pem cacert.pem ca.csr ca.srl
client.cert.pem client.csr client.key.pem
server.cert.pem server.csr server.key.pem
其中client.csr与server.csr只作用于证书申请功能需要CA证书颁发


#1,CA证书
openssl req -newkey rsa:2048 -nodes -keyout ca_rsa_private.pem -x509 -days 365 -out ca.crt -subj "/C=CN/ST=GD/L=SZ/O=COM/OU=NSP/CN=CA/emailAddress=aaaa@qq.com"

#2,服务器私钥与待签名
openssl req -newkey rsa:2048 -nodes -keyout server_rsa_private.pem  -out server.csr -subj "/C=CN/ST=GD/L=SZ/O=COM/OU=NSP/CN=SERVER/emailAddress=aaa@qq.com"

#3,使用CA证书及密钥对服务器证书进行签名
openssl x509 -req -days 365 -in server.csr -CA ca.crt -CAkey ca_rsa_private.pem -CAcreateserial -out server.crt

#######
openssl verify -CAfile ca.crt server.crt

#4, client
openssl req -newkey rsa:2048 -nodes -keyout client_rsa_private.pem -out client.csr -subj "/C=CN/ST=GD/L=SZ/O=COM/OU=NSP/CN=CLIENT/emailAddress=youremail@qq.com"

#5 使用CA证书及密钥对客户端证书进行签名:
openssl x509 -req -days 365 -in client.csr -CA ca.crt -CAkey ca_rsa_private.pem -CAcreateserial -out client.crt

openssl verify -CAfile ca.crt client.crt 

参考链接

https://www.cnblogs.com/Anker/p/6018032.html #基于openssl的单向和双向认证(有问题,双向认证的时候)

https://blog.csdn.net/weixin_34363171/article/details/86005536 注意在服务器做验证客户端证书 SSL_get_verify_result

Qt WebSockets Examples

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值