Skip to content

Instantly share code, notes, and snippets.

@alexzorin
Last active August 13, 2020 05:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save alexzorin/7aa3bfb7ec8be7b4a83baf6e2ba06a6c to your computer and use it in GitHub Desktop.
Save alexzorin/7aa3bfb7ec8be7b4a83baf6e2ba06a6c to your computer and use it in GitHub Desktop.
ASIO Let's Encrypt server and client example

Client relies on ctx.load_verify_file("cacert.pem"); being present, from https://curl.haxx.se/docs/caextract.html .

If you comment that line out, connecting to your server will give a verification failure:

$ ./client
Fatal error: handshake: certificate verify failed

If you leave it in, it will connect and verify successfully:

$ ./client
Read: Hello World
#include <iostream>
#include <boost/asio.hpp>
#include <boost/asio/ssl/stream.hpp>
#include <boost/beast/core/buffers_to_string.hpp>
#include <boost/asio/ssl/rfc2818_verification.hpp>
int main(int argc, char *argv[])
{
try
{
boost::asio::ssl::context ctx{boost::asio::ssl::context::tlsv12};
// Verify the server's certificate.
ctx.set_verify_mode(boost::asio::ssl::verify_peer);
ctx.set_verify_callback(boost::asio::ssl::rfc2818_verification("dragonosman.dynu.net"));
// Load cacerts from bundled cacert.pem file
// From https://curl.haxx.se/docs/caextract.html
// If you comment this out, verification will fail on connect
ctx.load_verify_file("cacert.pem");
// Connect the socket
boost::asio::io_context ioc{1};
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> ssl_socket(ioc, ctx);
boost::asio::ip::tcp::socket::lowest_layer_type &socket = ssl_socket.lowest_layer();
boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::address::from_string("127.0.0.1"), 8080);
boost::system::error_code ec;
socket.connect(endpoint, ec);
// Perform TLS handshake (and verification)
ssl_socket.handshake(boost::asio::ssl::stream_base::client);
// Read a simple message
boost::asio::streambuf buf;
boost::asio::read_until(ssl_socket, buf, '\n');
std::cout << "Read: " << boost::beast::buffers_to_string(buf.data()) << std::endl;
// Quit the TLS session
ssl_socket.shutdown();
}
catch (boost::system::system_error err)
{
std::cerr << "Fatal error: " << err.what() << std::endl;
return 1;
}
return 0;
}
#include <boost/asio.hpp>
#include <boost/asio/ssl/stream.hpp>
#include <iostream>
const std::string FULLCHAIN =
"-----BEGIN CERTIFICATE-----\n"
"MIIFXzCCBEegAwIBAgISA3TLN5zpw7Nz56DQlesDU0frMA0GCSqGSIb3DQEBCwUA\n"
"MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD\n"
"ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xOTAzMDQyMzI3MDdaFw0x\n"
"OTA2MDIyMzI3MDdaMB8xHTAbBgNVBAMTFGRyYWdvbm9zbWFuLmR5bnUubmV0MIIB\n"
"IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqtWF0MAUxTexmI0PN+AEIexk\n"
"m6w6srfLfjlDUx6YIUgBjBZs+UTyZwhlw4TkbGUJlcHgomJhiavBvjNZhmqYnhcE\n"
"s7RZ2G9yaWxpvzy4SUf7NEC7MSRanuTLrFHM29MAX42BsB2crax87cFkmNFBcN9Y\n"
"9WTWaasd4bgmUUohBqxUPkRv3KQLBW6jR0uAomRJjy5iF1RDkMRt46KOVh1Mv619\n"
"nJc/EOY7AkJTAcoegXimVR7aLJb/j61DhBrFwD+tJxrIW3jv417/fLGXHIxAbiY5\n"
"FT9ZcSHELXHsgSwUimlKUEon8fLAZooNAQRwl3nCIEhHMu5tiA3nCou5HpgpOQID\n"
"AQABo4ICaDCCAmQwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMB\n"
"BggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBTihU/ykkKhmo3ohkXq\n"
"n+FZh9zI2TAfBgNVHSMEGDAWgBSoSmpjBH3duubRObemRWXv86jsoTBvBggrBgEF\n"
"BQcBAQRjMGEwLgYIKwYBBQUHMAGGImh0dHA6Ly9vY3NwLmludC14My5sZXRzZW5j\n"
"cnlwdC5vcmcwLwYIKwYBBQUHMAKGI2h0dHA6Ly9jZXJ0LmludC14My5sZXRzZW5j\n"
"cnlwdC5vcmcvMB8GA1UdEQQYMBaCFGRyYWdvbm9zbWFuLmR5bnUubmV0MEwGA1Ud\n"
"IARFMEMwCAYGZ4EMAQIBMDcGCysGAQQBgt8TAQEBMCgwJgYIKwYBBQUHAgEWGmh0\n"
"dHA6Ly9jcHMubGV0c2VuY3J5cHQub3JnMIIBAwYKKwYBBAHWeQIEAgSB9ASB8QDv\n"
"AHUA4mlLribo6UAJ6IYbtjuD1D7n/nSI+6SPKJMBnd3x2/4AAAFpSz80pwAABAMA\n"
"RjBEAiAgl6RGuZkvNfd/247p6fah47zl0fSd/d8fprPCpLSDAwIgMurlg3mWl9o2\n"
"CQJALtExEtWCnVWNK5sqBPUjoTZGbE0AdgBj8tvN6DvMLM8LcoQnV2szpI1hd4+9\n"
"daY4scdoVEvYjQAAAWlLPzT8AAAEAwBHMEUCIAiH2mukKbbc0BU1bekMCJw3Y094\n"
"k3CtrtgWGA/DdtKmAiEApgV4P0z9Av89SkIZoz5Xlpp/z2dr7sgYT7KWFFopTAkw\n"
"DQYJKoZIhvcNAQELBQADggEBAAjDFHBf+ErtUeeFBY0VcdhkPhJD8gBXjLrX5SJY\n"
"uOmYmbumOkxJV0FFUWn7lZwvzhOmY6Y74Kq5n1iXSmax+SV+aayKvnE/sCpGnunF\n"
"YfLw7xykxGCjCleR/RQ0WnO3SMIC/EhQwmaf0EXQUMw1quQ+XF80sxGeb30Ys4JA\n"
"RvAkqdZXFI1Doif+FCoGpgqG6IvCMN8omdGM67HTLsDsY/EBR4NiSQX7D1KP5s/b\n"
"oeKhgtaNYEZN4h3tEthjHJYsZHEyiZCf99n9hXWxCUK3Xp3xKSK8rJYEQoLEBxo7\n"
"mb+0sWMI2ILdfAWO+Eo3Vvm1lt/JPGj/EgjC6vNYs5l9Kec=\n"
"-----END CERTIFICATE-----\n"
"-----BEGIN CERTIFICATE-----\n"
"MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/\n"
"MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT\n"
"DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow\n"
"SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT\n"
"GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC\n"
"AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF\n"
"q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8\n"
"SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0\n"
"Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA\n"
"a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj\n"
"/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T\n"
"AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG\n"
"CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv\n"
"bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k\n"
"c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw\n"
"VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC\n"
"ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz\n"
"MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu\n"
"Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF\n"
"AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo\n"
"uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/\n"
"wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu\n"
"X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG\n"
"PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6\n"
"KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==\n"
"-----END CERTIFICATE-----\n";
const std::string PRIVKEY =
"-----BEGIN RSA PRIVATE KEY-----\n"
"MIIEpQIBAAKCAQEAqtWF0MAUxTexmI0PN+AEIexkm6w6srfLfjlDUx6YIUgBjBZs\n"
"+UTyZwhlw4TkbGUJlcHgomJhiavBvjNZhmqYnhcEs7RZ2G9yaWxpvzy4SUf7NEC7\n"
"MSRanuTLrFHM29MAX42BsB2crax87cFkmNFBcN9Y9WTWaasd4bgmUUohBqxUPkRv\n"
"3KQLBW6jR0uAomRJjy5iF1RDkMRt46KOVh1Mv619nJc/EOY7AkJTAcoegXimVR7a\n"
"LJb/j61DhBrFwD+tJxrIW3jv417/fLGXHIxAbiY5FT9ZcSHELXHsgSwUimlKUEon\n"
"8fLAZooNAQRwl3nCIEhHMu5tiA3nCou5HpgpOQIDAQABAoIBAQCKruqCK9zwuaTI\n"
"FgN7tbVFINYP9oJ0YXamUrBQAu83XXA8HFx9A7bRY+TRE8ooIOHmHE1TJhDOpYuT\n"
"77XGxDR/ampbxJaHePnlkahLImzsuK26nq4YV83lXhHmI0XuUt3jtEnLAk8WQofs\n"
"r2oOERpSGk7qb+EMSWjpvAgHR+mFsv7CmU714XfYZ1hQJ5YV1m/q31O9KO+ctBEZ\n"
"ReyTFKoYMUkD8lcAgXfU5O4Oj6XOe+RNd9X1O+evzoLLEnheemxOHFEUowQ7QK1F\n"
"rvhLva2sAJ8gionvESiRNNoEBXhD94Z9YapkrxTvECiq49FnnkVxBUAgIOpm/mk9\n"
"TGz6BcztAoGBANeFrrEUrOE2b37XhT5bGby8xsQeYjx8nvhEcqLeV2A0SPc/T2Hd\n"
"gvEBKKAoJJ6SgxiMudgh8rTmlHIk7VyhMuWffotdNDrH1Vnu/4hqRbnArMBnP+bG\n"
"jSgQIDeQfWI7UpFV/pDt2blhuO240EKA7D31zmKxTcxld7a45baHfKX7AoGBAMrr\n"
"O7H+0ApMB381QlasaaFix8gtyO+zOYBa7+UwQTvt+WKfG9KBQ48INCTwfn+olXgG\n"
"7+guzr8FFlKOGbMVRMPoobGhZ+HNfcwwsBlgBMMExJx4AHwm9sprz7YUxyONNGsl\n"
"4SK5RwZdHLnQ9heteaS3UCA2sZkTaoVajoDbuCtbAoGBAISpEMKHS3LFIxQcbTPY\n"
"t5rpSB/n4+f/fYqr9zQxT+8zv8YQ/jfrNXJLmEoc641/+Zne5XYYT2DynWU1PbXK\n"
"s52L80StdjzITJcy+a9qWsjfxHYaF8dhZ/nFE0+gbM1OXqB/IlbrUR0+/am2HNsS\n"
"qFfrOcKeCJlLy8h5P0x/UUaJAoGAQjBCs4ebUpCELYEw11a7ydGPuwL8NPuv+Ocw\n"
"swBvdt3j58BgceSKJeCWKapsiLVzs8gHfyOtem9tXZZOWbTJTmHWRDuSx/ugWfdT\n"
"qaNBSl+Gxkb6WYTYISTTht/2KOmJPJ4JdqsauL+sfAvmCckjEZBdyXQtr/G+YCsu\n"
"qmeBBlsCgYEAmT81sY3UkwLWnHen7EgPvrIyEDZxgTkcQIppTK5YrXWC88g7gHhM\n"
"kQk45aQ0vxTtCVitnEfWAzW2YUMpWIxjKdKFNQFNfNRFfhoiQ83k2HcnZh6ROL/0\n"
"TcSryy4JJb6s08CvBOg0dH/GzVWtRWoiwQo0Hd0Etz1KG0zO0hMonp0=\n"
"-----END RSA PRIVATE KEY-----\n";
const std::string DHPARAM =
"-----BEGIN DH PARAMETERS-----\n"
"MIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz\n"
"+8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a\n"
"87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7\n"
"YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi\n"
"7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD\n"
"ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg==\n"
"-----END DH PARAMETERS-----\n";
int main(int argc, char *argv[])
{
boost::asio::io_context ioc{1};
boost::asio::ssl::context ctx{boost::asio::ssl::context::tlsv12};
ctx.use_certificate_chain(boost::asio::buffer(FULLCHAIN.data(), FULLCHAIN.size()));
ctx.use_rsa_private_key(boost::asio::buffer(PRIVKEY.data(), PRIVKEY.size()), boost::asio::ssl::context::file_format::pem);
ctx.use_tmp_dh(boost::asio::buffer(DHPARAM.data(), DHPARAM.size()));
boost::asio::ip::tcp::acceptor acceptor{ioc, {boost::asio::ip::make_address("0.0.0.0"), 8080}};
boost::system::error_code ec;
const char *msg = "Hello World\n";
for (;;)
{
try
{
// Accept a client connection
boost::asio::ip::tcp::socket socket{ioc};
acceptor.accept(socket);
boost::asio::ssl::stream<boost::asio::ip::tcp::socket &> stream{socket, ctx};
// Perform TLS handshake and verification
stream.handshake(boost::asio::ssl::stream_base::server, ec);
// Send a simple message
boost::asio::write(stream, boost::asio::buffer(msg, strlen(msg)));
// Bail out
stream.shutdown(ec);
}
catch (boost::system::system_error err)
{
std::cerr << "Connection error: " << err.what() << std::endl;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment