Project

General

Profile

Actions

Feature #1596

closed

support specifying a callback for SSL password used to read private key PEM files

Added by Anonymous almost 12 years ago. Updated over 11 years ago.

Status:
Closed
Priority:
High
Assignee:
Target version:
Start date:
12/04/2012
Due date:
% Done:

0%

Estimated time:

Description

It would be useful to have a way to specify a password callback from the application that hosts the WT server.

I think there should be a method provided by WServer class to specify the PasswordCalback to be used by boost::asio::ssl when reading the private key file.

Right now, only the default password callback from boost::asio::ssl is used which is displayed only in console mode.


Files

SslPasswordCallback.patch (3.29 KB) SslPasswordCallback.patch Wim Dumon, 04/17/2013 02:40 PM
SSLPWCB.patch (5.04 KB) SSLPWCB.patch W X, 04/18/2013 03:19 PM
Actions #1

Updated by Koen Deforche almost 12 years ago

  • Status changed from New to InProgress
  • Assignee set to Wim Dumon
Actions #2

Updated by Wim Dumon almost 12 years ago

  • Status changed from InProgress to Resolved
  • Target version set to 3.3.0
Actions #3

Updated by Koen Deforche almost 12 years ago

  • Status changed from Resolved to Closed
Actions #4

Updated by W X over 11 years ago

Hi,

The provided method for setting the SSL password callback has 2 issues:

- when called, the application crashes (I think the ssl_context_ is created only after calling start(), therefore it is invalid when setting the callback before start, as recommended. Calling it after calling start will probably have no effect with current implementation). It should still be set before start(), but is shouldn't crash so maybe it should be stored somewhere and set inside start()).

- it has only 1 parameter. The SSL callback expected by boost::asio has 2 (same as the underlying OpenSSL), see boost::asio::ssl::basic_context.hpp:

\" * `param callback The function object to be used for obtaining the password.

  • The function signature of the handler must be:
  • `code std::string password_callback(

    • std::size_t max_length, // The maximum size for a password.
    • password_purpose purpose // Whether password is for reading or writing.
    • ); @endcode
    • The return value of the callback is a string containing the password. \"

Can you please correct this ? In which release should the fix be expected ? It would be useful to have a patch with the fix before the release.

Thank you!

Actions #5

Updated by W X over 11 years ago

Is it really necessary to call boost::bind(cb, _1) inside Server::setSslPasswordCallback ? I guess the caller of WServer::setSslPasswordCallback should provide a binded callback, something like this:

WebServer.setSslPasswordCallback(boost::bind(&Class::callback, this, _1))... well there should be 2 parameters...

Actions #6

Updated by Wim Dumon over 11 years ago

The idea is to throw away the second parameter here. It will be 'for_reading' anyway, since we never write certificates in the httpd. Am I mistaken? What would you do with the second parameter?

I'm not sure why this call crashes. ssl_context_ is created int he constructor, so your claim in your first post doesn't seem correct to me. Do you have a stack trace?

BR,

Wim.

Actions #7

Updated by W X over 11 years ago

Regarding the number of parameters for the callback, basically using only the first should be OK for WT server as usually the callback is used for reading.

But what I can say is that in boost\asio\ssl\detail\openssl_context_service.hpp it is called with 2 parameters (I'm not sure whether the second parameter is ignored in this case):

static int password_callback(char* buf, int size, int purpose, void* data)
{
    if (data)
    {
      password_callback_type* callback =
        static_cast<password_callback_type*>(data);
      std::string passwd = (*callback)(static_cast<std::size_t>(size),
          purpose ? context_base::for_writing : context_base::for_reading);
    ...
}

and it is typedef-ed as:

  // The type for the password callback function object.
  typedef boost::function<std::string(std::size_t,
      context_base::password_purpose)> password_callback_type;

Regarding the crash, the way I see it working, based on the call stack, is that the Impl::Server is created during the WServer::start(). Impl::Server constructor initializes the ssl_context_ also. So the issue might be that the ssl_context_ is not initialized before calling WServer::start().

    .dll!http::server::Server::Server(const http::server::Configuration & config={...}, Wt::WServer & wtServer={...})  Line 77  C++
    .dll!Wt::WServer::start()  Line 150 + 0x47 bytes    C++

which is called after calling WServer::setSslPasswordCallback. The stack for the crash is:

    ntdll.dll!NtRaiseException()  + 0x12 bytes  
    [Frames below may be incorrect and/or missing, no symbols loaded for ntdll.dll] 
>   .dll!http::server::Server::setSslPasswordCallback(boost::function<std::basic_string<char,std::char_traits<char>,std::allocator<char> > __cdecl(unsigned int)> cb={...})  Line 241   C++
    .dll!Wt::WServer::setSslPasswordCallback(boost::function<std::basic_string<char,std::char_traits<char>,std::allocator<char> > __cdecl(unsigned int)> cb={...})  Line 235    C++

I'm calling WServer::setSslPasswordCallback with this callback:

std::string ssl_callback(std::size_t);

WServerObj.setSslPasswordCallback(boost::bind(&Object::ssl_callback, this, _1));
Actions #8

Updated by Wim Dumon over 11 years ago

Please try patch attached. If it works for you, it will get in the next release.

Wim.

Actions #9

Updated by W X over 11 years ago

Thanks for the quick response. I will try it, but I would have a few questions regarding the implementation:

- is it really necessary to use WT_API for the callback declaration in WServer (in my opinion it should not be dllexport-ed). As a matter of fact it shouldn't be accessible to the outside world in any way (since this callback exposes sensible data).

So, this would be my other questions:

- does the provided implementation makes sure that the callback will not be accessible, once set, to anyone else than the Server implementation ?

  • is there any approach to store it in one place only (in WServer or the server configuration). Or at least clear it from the WServer after setting it into the server configuration.

I think that using the callback should be as limited as possible to the area where is needed.

Actions #10

Updated by Wim Dumon over 11 years ago

  • Status changed from Closed to Feedback

Hi,

Consider the WT_API a mistake. It's probably even a compile error (not a static member) - I did not yet submit this to our build servers.

Would you be more comfortable if you could remove the password callback by setting a new (empty) one after start() returns? I'm just guessing here, but probably once the certificates are loaded, OpenSSL does not call it anymore. Can you verify that for me?

BR,

Wim.

Actions #11

Updated by W X over 11 years ago

Hi Wim,

Unfortunately after applying your patch, the code didn't even compile on my system. I get this error in Server.C:

- compiler error in Server.C
    if (config_.hasSslPasswordCallback())
      ssl_context_.set_password_callback(config_.sslPasswordCallback());
      2>Server.C
      2><>\BOOST\boost_1_46_1\boost/function/function_template.hpp(132) : *error C2064: term does not evaluate to a function taking 2 arguments*

I would have other suggestions also:

- reduce the redundancy of using boost::function<std::string (std::size_t max_length)> with a typedef

  • callback related code should be guarded with ifdef HTTP_WITH_SSL (?)

I have attached a patch with my code for specifying the SSL callback (it is a merge between some code that I have used before having this implemented in WT and your proposed patch). Please have a look and if you consider feel free to use it. It was tested and it works for me (it compiles and runs correctly).

What I don't like is that I had to duplicate the typedef of the ssl callback type in WServer and src/http/Configuration.h because the two are not visible to each other.

I hope this will not change very much in the next release so I don't have to modify my client code.

Actions #12

Updated by W X over 11 years ago

To aoid storing the callback in WServer.C::Impl and in http::Configuration I would do this:

void WServer::setSslPasswordCallback(ssl_password_cb_t cb)
{
  BOOST_ASSERT(impl_->serverConfiguration_);
  impl_->serverConfiguration_->setSslPasswordCallback(cb_);
}

and have the documentation in WServer changed:

  /*! \brief Change input method for server certificate passwords (http backend)
   *
   * ...
   * This function must be called after *setServerConfiguration* and before calling start().
   *
   * ...
   */
  WT_API void setSslPasswordCallback(ssl_password_cb_t cb);

That would be OK too, but would be a bit uglier if the user calls this method before setServerConfiguration due to the assert.

Actions #13

Updated by Wim Dumon over 11 years ago

  • Status changed from Feedback to Resolved
  • Target version changed from 3.3.0 to 3.3.1

fixed

Actions #14

Updated by Koen Deforche over 11 years ago

  • Status changed from Resolved to Closed
Actions

Also available in: Atom PDF