服务器代码(boost实现)
#pragma warning(disable : 4996)
#include <cstdlib>
#include <iostream>
#include <boost/bind.hpp>
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> ssl_socket;
class session
{
public:
session(boost::asio::io_service& io_service, boost::asio::ssl::context& context)
: socket_(io_service, context)
{
}
ssl_socket::lowest_layer_type& socket()
{
return socket_.lowest_layer();
}
void start()
{
socket_.async_handshake(boost::asio::ssl::stream_base::server,
boost::bind(&session::handle_handshake, this,
boost::asio::placeholders::error));
}
void handle_handshake(const boost::system::error_code& error)
{
if (!error)
{
std::cout << "handshake success" << std::endl;
socket_.async_read_some(boost::asio::buffer(data_, max_length),
boost::bind(&session::handle_read, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
else
{
std::cout << error.message() << std::endl;
delete this;
}
}
void handle_read(const boost::system::error_code& error,
size_t bytes_transferred)
{
if (!error)
{
std::cout << "handle_read success:"<< std::string(data_, bytes_transferred) << std::endl;
boost::asio::async_write(socket_,
boost::asio::buffer(data_, bytes_transferred),
boost::bind(&session::handle_write, this,
boost::asio::placeholders::error, _2));
}
else
{
std::cout << "handle_read error" << std::endl;
delete this;
}
}
void handle_write(const boost::system::error_code& error, size_t bytes_transferred)
{
if (!error)
{
std::cout << "handle_write success bytes_transferred:" << bytes_transferred << std::endl;
socket_.async_read_some(boost::asio::buffer(data_, max_length),
boost::bind(&session::handle_read, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
else
{
std::cout << "handle_write error" << std::endl;
delete this;
}
}
private:
ssl_socket socket_;
enum { max_length = 1024 };
char data_[max_length];
};
bool verify_callback(bool preverified, boost::asio::ssl::verify_context& ctx)
{
char subject_name[256];
X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle());
X509_NAME_oneline(X509_get_subject_name(cert), subject_name, 256);
std::cout << "subject_name:" << subject_name << std::endl;
return true;
}
class server
{
public:
server(boost::asio::io_service& io_service, unsigned short port)
: io_service_(io_service),
acceptor_(io_service,
boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string("192.168.1.102"), port)),
context_(boost::asio::ssl::context::sslv23)
{
context_.set_options(
boost::asio::ssl::context::default_workarounds
| boost::asio::ssl::context::no_sslv2
| boost::asio::ssl::context::single_dh_use);
//context_.set_password_callback(boost::bind(&server::get_password, this, _1, _2));
context_.use_certificate_chain_file("server.crt");
context_.use_private_key_file("private_server.key", boost::asio::ssl::context::pem);
context_.set_default_verify_paths();
context_.set_verify_mode(boost::asio::ssl::verify_peer | boost::asio::ssl::verify_fail_if_no_peer_cert);
context_.set_verify_callback(verify_callback);
session* new_session = new session(io_service_, context_);
acceptor_.async_accept(new_session->socket(),
boost::bind(&server::handle_accept, this, new_session,
boost::asio::placeholders::error));
}
std::string get_password(std::size_t max_length, boost::asio::ssl::context_base::password_purpose password_purpose)
{
std::cout << "get_password" << std::endl;
return "boost Server";
}
void handle_accept(session* new_session,
const boost::system::error_code& error)
{
if (!error)
{
std::cout << "accept success" << std::endl;
new_session->start();
new_session = new session(io_service_, context_);
acceptor_.async_accept(new_session->socket(),
boost::bind(&server::handle_accept, this, new_session,
boost::asio::placeholders::error));
}
else
{
std::cout << "accept error" << std::endl;
delete new_session;
}
}
private:
boost::asio::io_service& io_service_;
boost::asio::ip::tcp::acceptor acceptor_;
boost::asio::ssl::context context_;
};
int main(int argc, char* argv[])
{
boost::asio::io_service io_service;
boost::asio::io_service::work work(io_service);
using namespace std; // For atoi.
server s(io_service, 20000);
io_service.run();
return 0;
}
客户端(boost实现)
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/bind.hpp>
#include <iostream>
using namespace boost::asio;
bool verify_callback(bool preverified, boost::asio::ssl::verify_context& ctx)
{
char subject_name[256];
X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle());
X509_NAME_oneline(X509_get_subject_name(cert), subject_name, 256);
std::cout << "subject_name:" << subject_name << std::endl;
return true;
}
io_service service;
int main(int argc, char* argv[]) {
typedef ssl::stream<ip::tcp::socket> ssl_socket;
ssl::context ctx(ssl::context::sslv23);
ctx.set_default_verify_paths();
ctx.set_options(
boost::asio::ssl::context::default_workarounds
| boost::asio::ssl::context::no_sslv2
| boost::asio::ssl::context::single_dh_use);
ctx.use_certificate_chain_file("cilent.crt");
ctx.use_private_key_file("private_cilent.key", boost::asio::ssl::context::pem);
// 打开一个到指定主机的ssl socket
io_service service;
ssl_socket sock(service, ctx);
boost::system::error_code code;
sock.lowest_layer().connect(ip::tcp::endpoint(ip::address::from_string("192.168.1.102"), 20000), code);
if (code)
{
std::cout << "connect error" << std::endl;
return 0;
}
std::cout << "connect success" << std::endl;
// ssl 握手
sock.set_verify_mode(ssl::verify_peer | ssl::verify_fail_if_no_peer_cert);
sock.set_verify_callback(verify_callback);
boost::system::error_code ec;
sock.handshake(ssl_socket::client);
std::string req = "get /index.html http/1.0\r\nhost: 172.16.8.118\r\naccept: */*\r\nconnection: close\r\n\r\n";
write(sock, buffer(req.c_str(), req.size()));
char buff[512];
while (true) {
int bytes = read(sock, buffer(buff, 80), ec);
if (bytes > 0)
{
std::cout << "bytes:" << bytes << std::string(buff, bytes);
}
}
return 1;
}
客户端(QT实现)
QFile file("D:/Users/Documents/untitled111/cilent.crt");
if(!file.open(QIODevice::ReadOnly))
return;
QSslCertificate cert(file.readAll());
if(cert.isNull())
return;
QFile key("D:/Users/Documents/untitled111/private_cilent.key");
if(!key.open(QIODevice::ReadOnly))
return;
QSslKey clientKey(key.readAll(), QSsl::Rsa);
QSslConfiguration config;
config.setPrivateKey(clientKey);
config.setLocalCertificate(cert);
config.setPeerVerifyMode(QSslSocket::VerifyPeer);
// config.setCiphers(QList<QSslCipher>()<<QSslCipher("PSK-AES128-CBC-SHA256"));
QList<QSslCipher> ls = config.supportedCiphers();
// for(int i=0;i<ls.count();i++)
// {
// qDebug()<<"****"<<ls.at(i).name();
// }
m_sslSocket.setSslConfiguration(config);
m_sslSocket.setProtocol(QSsl::SecureProtocols);
// connect(&m_sslSocket, &QSslSocket::preSharedKeyAuthenticationRequired, [=](QSslPreSharedKeyAuthenticator *authenticator)
// {
// authenticator->setIdentity("QT user");
// authenticator->setPreSharedKey("1111111222222222222223333333333333333");
// qDebug()<<"---------------------------------------";
// });
connect(&m_sslSocket, &QSslSocket::peerVerifyError, [=](const QSslError &error){
QSslCertificate c = error.certificate();
qDebug()<< "cert:" << c.issuerDisplayName() << " error:" << error.errorString();
m_sslSocket.ignoreSslErrors();
});
connect(&m_sslSocket, &QSslSocket::encrypted, [=]()
{
m_sslSocket.write("get /index.html http/1.0\r\nhost: 172.16.8.118\r\naccept: */*\r\nconnection: close\r\n\r\n");
});
connect(&m_sslSocket, &QSslSocket::readyRead, [=]()
{
qDebug()<<"======";
qDebug()<<m_sslSocket.readAll();
});
m_sslSocket.connectToHostEncrypted("192.168.1.102", 20000);
证书与私钥
服务端和客户端各持有证书和私钥,其中证书是由自建CA机构颁发。
利用openssl生成证书和私钥
生成CA自签名根证书和颁发证书
TLS链路协商加密协议方式
1、由客户端发起Client Hello请求,其中带有支持的SSL协议以及支持的加密算法;
同时交换本地生成的随机数和a*G
2、服务端根据客户端支持的加密算法和SSL版本,选择后发送Server Hello和b*G,以及数据等
3、进行加密数据传输(交互)