Corvusoft / restbed

Corvusoft's Restbed framework brings asynchronous RESTful functionality to C++14 applications.
http://www.corvusoft.co.uk
Other
1.93k stars 379 forks source link

Unable to use ECDHE-ECDSA-AES128-SHA256 cipher suite with Restbed #86

Open markelkins opened 8 years ago

markelkins commented 8 years ago

I need to use HTTPS with the ECDHE-ECDSA-AES128-SHA256 cipher suite, but I cannot seem to get Restbed to use this cipher suite. The error I get is "no shared cipher" when I connect using cURL and specify the cipher suite above. I have configured the server to use a ECC secp256p1 keypair. Any thoughts on how to get this working? I'm working on Darwin 10.3.

For reference here is the code I have so far for the server:

#include <memory>
#include <cstdlib>
#include <restbed>

#include "stderr_logger.h"

using namespace std;
using namespace restbed;

/**
 * POST request handler for /ping endpoint. Returns 204 NO CONTENT.
 */
void ping_post_method_handler(const shared_ptr<Session> session)
{
    const auto request = session->get_request();

    size_t content_length = 0;
    request->get_header("Content-Length", content_length);

    session->fetch(
        content_length, [request](const shared_ptr< Session > session, const Bytes & body)
    {
        fprintf(stdout, "%.*s\n", (int) body.size(), body.data());
        session->close(NO_CONTENT, "", {{"Content-Length", "0"}, {"Connection", "close"}});
    } );
}

/**
 * GET request handler for /ping endpoint. Returns 204 NO CONTENT.
 */
void ping_get_method_handler(const shared_ptr< Session > session)
{
    session->close(NO_CONTENT);
}

int main(const int argc, const char** argv)
{
int portNumber = 443;

    if (argc > 1) { // See if port number is specified.
        portNumber = atoi(argv[1]);
    }

    auto pingEndpoint = make_shared<Resource>();
    pingEndpoint->set_path("/ping");
    pingEndpoint->set_method_handler("GET", ping_get_method_handler);
    pingEndpoint->set_method_handler("POST", ping_post_method_handler);

    auto sslSettings = make_shared<SSLSettings>();
    sslSettings->set_http_disabled(true);
    sslSettings->set_port(portNumber);
    sslSettings->set_private_key(Uri("file://ec_privkey.pem"));
    sslSettings->set_certificate(Uri("file://server.crt"));
    sslSettings->set_temporary_diffie_hellman("file://ec_params.pem");

    auto settings = make_shared<Settings>();
    settings->set_ssl_settings(sslSettings);

    Service service;
    service.publish(pingEndpoint);
    service.set_logger(make_shared<StdErrLogger>());
    service.start(settings);

    return EXIT_SUCCESS;
}

Here are the key files I am using. (Don't worry, they are only temporary keys.)

ec_privkey.pem

-----BEGIN EC PARAMETERS-----
BggqhkjOPQMBBw==
-----END EC PARAMETERS-----
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIHp42wxVJLTXAHYCv7SXRjyzabukVYeYeCFtE6P6zV1YoAoGCCqGSM49
AwEHoUQDQgAER/NBX0PrUH3PbsI55tlyQhPZtrnoVWQ7knzPD+rApFmu+3OdDhen
G6m8lp1tQzcP6LgOmxy2KnUYXtchbLjqbA==
-----END EC PRIVATE KEY-----

server.crt

-----BEGIN CERTIFICATE-----
MIIBzTCCAXQCCQChyOJTWfQbiDAKBggqhkjOPQQDAjBvMQswCQYDVQQGEwJDQTEQ
MA4GA1UECAwHT250YXJpbzERMA8GA1UEBwwIV2F0ZXJsb28xHjAcBgNVBAoMFVRy
dXN0UG9pbnQgSW5ub3ZhdGlvbjEbMBkGA1UEAwwSVHJ1c3RQb2ludCBUZXN0IFJB
MB4XDTE2MDQxMTE5MDkzNVoXDTI2MDQwOTE5MDkzNVowbzELMAkGA1UEBhMCQ0Ex
EDAOBgNVBAgMB09udGFyaW8xETAPBgNVBAcMCFdhdGVybG9vMR4wHAYDVQQKDBVU
cnVzdFBvaW50IElubm92YXRpb24xGzAZBgNVBAMMElRydXN0UG9pbnQgVGVzdCBS
QTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABEfzQV9D61B9z27COebZckIT2ba5
6FVkO5J8zw/qwKRZrvtznQ4XpxupvJadbUM3D+i4Dpsctip1GF7XIWy46mwwCgYI
KoZIzj0EAwIDRwAwRAIgDiiPD9FSXOaLF1jMDfwv4ECbQtO0wnEUHpCLWl/kAZAC
ICJN84VDkmtrhNTTV7PCHCAK5en8TuPbvYHHtn8r8T0D
-----END CERTIFICATE-----
ben-crowhurst commented 8 years ago

Please present the commands used to generate certificates/parameters.

openssl genrsa -out ....

Whats the client command used, whats the output of the client command?

markelkins commented 8 years ago

The commands were:

openssl ecparam -name secp256r1 -out ec_privkey.pem -genkey openssl req -new -key ec_privkey.pem -out server.csr openssl x509 -req -days 3650 -in server.csr -signkey ec_privkey.pem -out server.crt

callum-kirby commented 8 years ago

What is the outcome from openssl ciphers -s.

ben-crowhurst commented 8 years ago

@markelkins I must mention that your organisation looks very security focused.

Please understand that Restbed is not currently working off the latest version of OpenSSL and 4.0 is on hold until ASIO has merged a pending PR.

If your organisation proceeds with commercial licensing we will reiterate this matter, if it remains unresolved.

markelkins commented 8 years ago

@ben-crowhurst I appreciate the warning. For now we are just building a server to test some other products we are working on. If we decide to commercialize our server work, we will definitely need to have more discussion with you.

conz27 commented 8 years ago

@markelkins

openssl ecparam -name secp256r1 -out ec_privkey.pem -genkey

Did this succeed?

I looked up openssl ecparam -list_curves, and secp256r1 was not in the list. The other name for secp256r1 is prime256v1 based on RFC-5480.

Just to be certain, it might be worth trying with -name prime256v1 in case that's confusing OpenSSL.

conz27 commented 8 years ago

Okay, so I've finally cracked this beast of a problem but I'm not sure that the fix belongs solely in Restbed's codebase. It's a flaw with Boost's ASIO SSL wrapper as well, because it doesn't contain mechanisms to support ECDHE.

Essentially, it's missing the necessary ASIO API to invoke the equivalent of: sslSettings->set_temporary_diffie_hellman("file://ec_params.pem"); , but for the ECC (Elliptic Curve Cryptography) implementation. Using set_temporary_diffie_hellman() will not work.

I have a hack fix in place that I've tested as working, but I need to figure out how to integrate it properly.

I think this will impact any & all algorithms that rely on ECDHE, not just the cipher mentioned in this issue.

ben-crowhurst commented 8 years ago

Please share the "hack", and great work 👍

conz27 commented 8 years ago

So essentially, restbed needs to implement a wrapper around the new ASIO function (from pull request above) in the SSL settings context and use it service_impl.cpp.

I've actually got a working wrapper implemented that I used to test ASIO - just need to clean it up a bit.

ben-crowhurst commented 7 years ago

This issue will be resolved with the 5.0 release, allowing any socket layer to be inserted into the framework. Public beta branch will be available July 2017.

ben-crowhurst commented 3 years ago

This will finally be possible July 2021. We will expose a NetworkAdaptor interface that will enable OpenSSL, LibreSSL or any other such functionality.