반응형
OpenSSL을 사용한 SSL/TLS 통신
OpenSSL은 SSL 및 TLS 프로토콜을 구현한 오픈 소스 라이브러리입니다. 이를 사용하여 네트워크 애플리케이션에서 안전한 통신을 구현할 수 있습니다. OpenSSL은 C/C++ 애플리케이션에서 쉽게 사용할 수 있으며, 다양한 암호화 알고리즘과 기능을 제공합니다.
OpenSSL 설치
Linux
- Debian/Ubuntu:
sudo apt-get install libssl-dev
- CentOS/RHEL:
sudo yum install openssl-devel
Windows
- Windows에서는 OpenSSL 공식 웹사이트에서 설치 파일을 다운로드하여 설치할 수 있습니다.
SSL/TLS 서버 구현
SSL/TLS 서버 코드 예제
AsyncSslServer.h
#ifndef ASYNCSSLSERVER_H
#define ASYNCSSLSERVER_H
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/beast.hpp>
#include <memory>
#include <iostream>
namespace beast = boost::beast; // Boost.Beast 네임스페이스
namespace net = boost::asio; // Boost.Asio 네임스페이스
namespace ssl = net::ssl; // SSL 네임스페이스
using tcp = net::ip::tcp; // TCP 네임스페이스
// 세션 클래스 정의
class Session : public std::enable_shared_from_this<Session> {
public:
// 생성자
explicit Session(tcp::socket socket, ssl::context& ctx)
: ssl_stream_(std::move(socket), ctx) {}
// 세션 실행
void run() {
auto self = shared_from_this();
ssl_stream_.async_handshake(ssl::stream_base::server,
[this, self](beast::error_code ec) {
if (!ec) {
do_read();
}
});
}
private:
// 데이터 읽기
void do_read() {
auto self = shared_from_this();
ssl_stream_.async_read_some(net::buffer(data_),
[this, self](beast::error_code ec, std::size_t length) {
if (!ec) {
do_write(length);
}
});
}
// 데이터 쓰기
void do_write(std::size_t length) {
auto self = shared_from_this();
net::async_write(ssl_stream_, net::buffer(data_, length),
[this, self](beast::error_code ec, std::size_t /*length*/) {
if (!ec) {
do_read();
}
});
}
ssl::stream<tcp::socket> ssl_stream_;
char data_[1024];
};
// 리스너 클래스 정의
class Listener : public std::enable_shared_from_this<Listener> {
public:
// 생성자
Listener(net::io_context& ioc, ssl::context& ctx, tcp::endpoint endpoint)
: acceptor_(ioc), socket_(ioc), ctx_(ctx) {
beast::error_code ec;
// 소켓 열기
acceptor_.open(endpoint.protocol(), ec);
if (ec) {
std::cerr << "오류: " << ec.message() << std::endl;
return;
}
// 소켓 옵션 설정
acceptor_.set_option(net::socket_base::reuse_address(true), ec);
if (ec) {
std::cerr << "오류: " << ec.message() << std::endl;
return;
}
// 바인딩
acceptor_.bind(endpoint, ec);
if (ec) {
std::cerr << "오류: " << ec.message() << std::endl;
return;
}
// 수신 대기
acceptor_.listen(net::socket_base::max_listen_connections, ec);
if (ec) {
std::cerr << "오류: " << ec.message() << std::endl;
return;
}
do_accept();
}
private:
// 연결 수락
void do_accept() {
acceptor_.async_accept(socket_,
[this](beast::error_code ec) {
if (!ec) {
std::make_shared<Session>(std::move(socket_), ctx_)->run();
}
do_accept();
});
}
tcp::acceptor acceptor_;
tcp::socket socket_;
ssl::context& ctx_;
};
#endif // ASYNCSSLSERVER_H
main.cpp
#include <iostream>
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <memory>
#include "AsyncSslServer.h"
namespace net = boost::asio;
using tcp = net::ip::tcp;
int main() {
try {
auto const address = net::ip::make_address("0.0.0.0");
auto const port = static_cast<unsigned short>(std::atoi("12345"));
net::io_context ioc{1};
ssl::context ctx{ssl::context::tlsv12};
ctx.set_options(ssl::context::default_workarounds
| ssl::context::no_sslv2
| ssl::context::single_dh_use);
// SSL 인증서와 키 설정
ctx.use_certificate_chain_file("server.crt");
ctx.use_private_key_file("server.key", ssl::context::pem);
std::make_shared<Listener>(ioc, ctx, tcp::endpoint{address, port})->run();
ioc.run();
} catch (const std::exception& e) {
std::cerr << "예외 발생: " << e.what() << std::endl;
}
return 0;
}
SSL/TLS 클라이언트 구현
SSL/TLS 클라이언트 코드 예제
AsyncSslClient.h
#ifndef ASYNCSSLCLIENT_H
#define ASYNCSSLCLIENT_H
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/beast.hpp>
#include <memory>
#include <iostream>
namespace beast = boost::beast; // Boost.Beast 네임스페이스
namespace net = boost::asio; // Boost.Asio 네임스페이스
namespace ssl = net::ssl; // SSL 네임스페이스
using tcp = net::ip::tcp; // TCP 네임스페이스
// SSL 클라이언트 클래스 정의
class AsyncSslClient : public std::enable_shared_from_this<AsyncSslClient> {
public:
// 생성자
AsyncSslClient(net::io_context& ioc, ssl::context& ctx)
: ssl_stream_(net::make_strand(ioc), ctx) {}
// 서버에 연결
void connect(const std::string& host, const std::string& port) {
tcp::resolver resolver(ssl_stream_.get_executor());
auto const results = resolver.resolve(host, port);
net::async_connect(ssl_stream_.next_layer(), results.begin(), results.end(),
[self = shared_from_this()](beast::error_code ec, tcp::resolver::results_type::endpoint_type) {
if (!ec) {
self->handshake();
}
});
}
private:
// 핸드셰이크
void handshake() {
auto self = shared_from_this();
ssl_stream_.async_handshake(ssl::stream_base::client,
[this, self](beast::error_code ec) {
if (!ec) {
do_write();
}
});
}
// 데이터 쓰기
void do_write() {
auto self = shared_from_this();
net::async_write(ssl_stream_, net::buffer("Hello from client"),
[this, self](beast::error_code ec, std::size_t length) {
if (!ec) {
do_read();
}
});
}
// 데이터 읽기
void do_read() {
auto self = shared_from_this();
ssl_stream_.async_read_some(net::buffer(data_),
[this, self](beast::error_code ec, std::size_t length) {
if (!ec) {
std::cout << "서버로부터 수신한 메시지: " << std::string(data_.data(), length) << std::endl;
}
});
}
ssl::stream<tcp::socket> ssl_stream_;
std::array<char, 1024> data_;
};
#endif // ASYNCSSLCLIENT_H
main.cpp
#include <iostream>
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <memory>
#include "AsyncSslClient.h"
namespace net = boost::asio;
using tcp = net::ip::tcp;
int main() {
try {
net::io_context ioc;
ssl::context ctx{ssl::context::tlsv12};
ctx.set_options(ssl::context::default_workarounds
| ssl::context::no_sslv2
| ssl::context::single_dh_use);
// SSL 인증서 설정 (Optional, 서버 인증서 검증)
ctx.load_verify_file("ca.crt");
auto client = std::make_shared<AsyncSslClient>(ioc, ctx
);
client->connect("127.0.0.1", "12345");
ioc.run();
} catch (const std::exception& e) {
std::cerr << "예외 발생: " << e.what() << std::endl;
}
return 0;
}
설명
위의 코드는 Boost.Asio와 OpenSSL을 사용하여 SSL/TLS 통신을 지원하는 클라이언트를 구현한 예제입니다. 이 클라이언트는 서버와의 SSL/TLS 연결을 설정하고, 데이터를 주고받는 기능을 제공합니다.
- AsyncSslClient 클래스:
AsyncSslClient
클래스는 SSL/TLS 클라이언트를 관리합니다. SSL 스트림을 사용하여 서버와 데이터를 주고받습니다.connect()
함수는 서버에 연결을 설정합니다.handshake()
함수는 서버와의 SSL/TLS 핸드셰이크를 수행합니다.do_write()
함수는 서버로 데이터를 비동기적으로 씁니다.do_read()
함수는 서버로부터 데이터를 비동기적으로 읽습니다.
이제 열여덟 번째 날의 학습을 마쳤습니다. OpenSSL을 사용한 SSL/TLS 통신의 기본 개념과 Boost.Asio와 OpenSSL을 사용하여 SSL/TLS 통신을 지원하는 클라이언트를 구현하는 방법을 학습했습니다.
질문이나 피드백이 있으면 언제든지 댓글로 남겨 주세요. 내일은 "네트워크 성능 최적화 기법"에 대해 학습하겠습니다.
반응형
'-----ETC----- > C++ 네트워크 프로그래밍 시리즈' 카테고리의 다른 글
[C++ 네트워크 프로그래밍] Day 20: 로드 밸런싱과 스케일링 (0) | 2024.08.01 |
---|---|
[C++ 네트워크 프로그래밍] Day 21: 네트워크 모니터링과 로깅 (0) | 2024.08.01 |
[C++ 네트워크 프로그래밍] Day 19: 네트워크 성능 최적화 기법 (0) | 2024.08.01 |
[C++ 네트워크 프로그래밍] Day 16: 비동기 I/O와 이벤트 드리븐 프로그래밍 (0) | 2024.08.01 |
[C++ 네트크 프로그래밍] Day 17: 네트워크 보안 기초 (SSL/TLS) (0) | 2024.08.01 |