diff --git a/CHANGELOG.md b/CHANGELOG.md index 1423460c..0bafe07a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ Version 73: * Jamroot tweak +* Verify certificates in SSL clients HTTP: diff --git a/example/common/root_certificates.hpp b/example/common/root_certificates.hpp new file mode 100644 index 00000000..502c30c6 --- /dev/null +++ b/example/common/root_certificates.hpp @@ -0,0 +1,117 @@ +// +// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BEAST_EXAMPLE_COMMON_ROOT_CERTIFICATES_HPP +#define BEAST_EXAMPLE_COMMON_ROOT_CERTIFICATES_HPP + +#include +#include + +namespace ssl = boost::asio::ssl; // from + +namespace detail { + +// The template argument is gratuituous, to +// allow the implementation to be header-only. +// +template +void +load_root_certificates(ssl::context& ctx, boost::system::error_code& ec) +{ + std::string const cert = + /* This is the DigiCert root certificate. + + CN = DigiCert High Assurance EV Root CA + OU = www.digicert.com + O = DigiCert Inc + C = US + + Valid to: Sunday, ?November ?9, ?2031 5:00:00 PM + + Thumbprint(sha1): + 5f b7 ee 06 33 e2 59 db ad 0c 4c 9a e6 d3 8f 1a 61 c7 dc 25 + */ + "-----BEGIN CERTIFICATE-----\n" + "MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs\n" + "MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n" + "d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j\n" + "ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL\n" + "MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3\n" + "LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug\n" + "RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm\n" + "+9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW\n" + "PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM\n" + "xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB\n" + "Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3\n" + "hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg\n" + "EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF\n" + "MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA\n" + "FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec\n" + "nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z\n" + "eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF\n" + "hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2\n" + "Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe\n" + "vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep\n" + "+OkuE6N36B9K\n" + "-----END CERTIFICATE-----\n"; + /* This is the GeoTrust root certificate. + + CN = GeoTrust Global CA + O = GeoTrust Inc. + C = US + Valid to: Friday, ‎May ‎20, ‎2022 9:00:00 PM + + Thumbprint(sha1): + ‎de 28 f4 a4 ff e5 b9 2f a3 c5 03 d1 a3 49 a7 f9 96 2a 82 12 + */ + "-----BEGIN CERTIFICATE-----\n" + "MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs\n" + "MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n" + "d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j\n" + "ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL\n" + "MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3\n" + "LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug\n" + "RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm\n" + "+9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW\n" + "PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM\n" + "xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB\n" + "Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3\n" + "hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg\n" + "EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF\n" + "MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA\n" + "FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec\n" + "nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z\n" + "eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF\n" + "hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2\n" + "Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe\n" + "vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep\n" + "+OkuE6N36B9K\n" + "-----END CERTIFICATE-----\n"; + + ctx.add_certificate_authority( + boost::asio::buffer(cert.data(), cert.size()), ec); + if(ec) + return; +} + +} // detail + +// Load the root certificates into an ssl::context +// +// This function is inline so that its easy to take +// the address and there's nothing weird like a +// gratuituous template argument; thus it appears +// like a "normal" function. +// +inline +void +load_root_certificates(ssl::context& ctx, boost::system::error_code& ec) +{ + detail::load_root_certificates(ctx, ec); +} + +#endif diff --git a/example/http-client-ssl/CMakeLists.txt b/example/http-client-ssl/CMakeLists.txt index 09d9ed48..3abb8b8d 100644 --- a/example/http-client-ssl/CMakeLists.txt +++ b/example/http-client-ssl/CMakeLists.txt @@ -1,11 +1,12 @@ # Part of Beast GroupSources(include/beast beast) - +GroupSources(example/common common) GroupSources(example/http-client-ssl "/") add_executable (http-client-ssl ${BEAST_INCLUDES} + ${COMMON_INCLUDES} http_client_ssl.cpp ) diff --git a/example/http-client-ssl/http_client_ssl.cpp b/example/http-client-ssl/http_client_ssl.cpp index 53f836a0..046b21fc 100644 --- a/example/http-client-ssl/http_client_ssl.cpp +++ b/example/http-client-ssl/http_client_ssl.cpp @@ -5,6 +5,8 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // +#include "../common/root_certificates.hpp" + #include #include #include @@ -46,10 +48,17 @@ int main() if(ec) return fail("connect", ec); + // Create the required ssl context + ssl::context ctx{ssl::context::sslv23_client}; + + // This holds the root certificate used for verification + load_root_certificates(ctx, ec); + if(ec) + return fail("certificate", ec); + // Wrap the now-connected socket in an SSL stream - ssl::context ctx{ssl::context::sslv23}; ssl::stream stream{sock, ctx}; - stream.set_verify_mode(ssl::verify_none); + stream.set_verify_mode(ssl::verify_peer | ssl::verify_fail_if_no_peer_cert); // Perform SSL handshaking stream.handshake(ssl::stream_base::client, ec); diff --git a/example/websocket-client-ssl/websocket_client_ssl.cpp b/example/websocket-client-ssl/websocket_client_ssl.cpp index 35ad063d..eb739f03 100644 --- a/example/websocket-client-ssl/websocket_client_ssl.cpp +++ b/example/websocket-client-ssl/websocket_client_ssl.cpp @@ -5,6 +5,8 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // +#include "../common/root_certificates.hpp" + #include #include #include @@ -47,9 +49,16 @@ int main() if(ec) return fail("connect", ec); + // Create the required ssl context + ssl::context ctx{ssl::context::sslv23_client}; + + // This holds the root certificate used for verification + load_root_certificates(ctx, ec); + if(ec) + return fail("certificate", ec); + // Wrap the now-connected socket in an SSL stream using stream_type = ssl::stream; - ssl::context ctx{ssl::context::sslv23}; stream_type stream{sock, ctx}; stream.set_verify_mode(ssl::verify_none);