Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SSL for HTTP server #2578

Closed
wants to merge 2 commits into from
Closed

Conversation

MightyPork
Copy link
Contributor

@MightyPork MightyPork commented Oct 17, 2018

This PR adds HTTPS capability to the HTTP server component. It is implemented using the already existing API, with some necessary tweaks. It also fixes a few bugs and issues I encountered, see below.

HTTP server changes:

  • add global user context (void *) in http_server config struct + getter routine
  • modify send/recv function signature to include server handle
  • add pending check function (overridable per socket)
  • remove mistaken trailing semicolon in HTTPD_DEFAULT_CONFIG()
  • add configurable "socket open handler" that can set up session context
  • add support for length = -1 in httpd_resp_send() -> use strlen()
  • add function to set session context by FD
  • add functions to set session send/recv/pending overrides by FD
  • FIX assert() if select fails - recovert by closing invalid sockets
  • Change shutdown waiting loop to use only 100ms wait time instead of 1s
  • make httpd_sess_get() non-static, it is now needed outside httpd_sess.c

HTTPS server component

  • new component that initializes the HTTP server with TLS support, taking
    advantage of the new APIs and tweaks
  • based on the OpenSSL server example
  • added example

@MightyPork MightyPork changed the title Tweak http_server to allow https support, add https_server component + example SSL for HTTP server Oct 17, 2018
@igrr igrr requested a review from mahavirj October 23, 2018 06:57
@mahavirj
Copy link
Member

@MightyPork

Thanks for your contribution. This PR involves API change, we are discussing ways in which that can be avoided at this moment (for getting web server handle, maybe we can use thread local storage instead). Will keep you posted on this.

Also just to give you heads up, component and header names for http_server component being too generic, resulting in trouble for some other users, so change to add esp prefix is already in our pieline. This will require rebase on this PR as well. Will let you know once we have this change integrated.

* - Bytes : The number of bytes sent successfully
* - -VE : In case of error
*/
typedef int (*httpd_send_func_t)(httpd_handle_t hd, int sockfd, const char *buf, size_t buf_len, int flags);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MightyPork This changes the API, which we would like to avoid

A workaround would be to define a new public function like httpd_get_server_handle(), and use that to extract the handle from inside your custom send/recv function.

Since the send/recv functions will always be invoked from inside the server thread, you could use pvTaskSetThreadLocalStoragePointer() to store the server handle during creation and later retrieve the handle from pvTaskGetThreadLocalStoragePointer().

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this can be done, but it seems needlessly convoluted to me. Is there a reason to worry about API changes, if the http_server component is still unreleased in a stable version? (this is why I'm using master instead of the stable release)

while we're discussing it, what was the original purpose of the send / recv override functions? Because if they are used for SSL handling, they become unavailable for anything else.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason to worry about API changes, if the http_server component is still unreleased in a stable version?

Your are right. But my only concern is that people might have already started using the API. Still let me discuss this and get back to you.

while we're discussing it, what was the original purpose of the send / recv override functions?

The purpose was to allow for extension/encryption/encapsulation of HTTP packets as per requirement, just like you are using it for SSL

Because if they are used for SSL handling, they become unavailable for anything else.

That is alright. They are intended to allow one layer of extension only. Now in case someone requires something fancy with SSL as well as some form of encapsulation then she will have to start implementing on top of http_server.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MightyPork After some discussion we have concluded that changing the API should be alright in this case, like you said

*/
static int httpdssl_recv(httpd_handle_t server, int sockfd, char *buf, size_t buf_len, int flags)
{
SSL *ssl = httpd_sess_get_ctx(server, sockfd);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Session context is passed along with the httpd_req_t structure when URI handler is executed. It's useful for session persistence (See the persistent_sockets example).

Could you use a different member variable (and corresponding APIs) for saving and accessing the pointer to SSL object. Maybe call it priv_ctx or internal_ctx?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure. in that case, do you want to keep the functions httpd_sess_get_ctx / httpd_sess_set_ctx that I added for this purpose as well as adding new ones for this 'internal_ctx'?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can keep them. They may come handy sometime.

@anurag-kar
Copy link
Contributor

There seem to be conflicts in

components/http_server/include/http_server.h
components/http_server/src/httpd_txrx.c

Could you please resolve them?

@MightyPork
Copy link
Contributor Author

There seem to be conflicts in

components/http_server/include/http_server.h
components/http_server/src/httpd_txrx.c

Could you please resolve them?

sure, I plan to have a look at it tonight (GMT+1) and fix this + the other issues

@MightyPork
Copy link
Contributor Author

@anurag-kar can you please review the changes? it's rebased and should be ready to merge
I added some github comments to the code, but it made quite a mess here so i closed them again lol

it now uses 'transport_ctx' instead of 'ctx'

@anurag-kar
Copy link
Contributor

anurag-kar commented Oct 27, 2018

@MightyPork I'm in the process of reviewing, but because I am supposed to travel for the upcoming 2-3 days, so it may take some time.

I see the github comments you've put and I find them helpful.

transport_ctx is an appropriate name actually.

There was another http_server related commit that got merged which changes the component path and name to esp_http_server. So you will have to resolve the conflicts again. Please bear with us.

We are looking forward to have your pull request so I'll hold of any more changes to esp_http_server from our side till this is merged.

Also, could you add a close_fn callback (just like the open_fn) which gets invoked when a session/socket is closed. This may not be useful for HTTPS but there are some of our applications where having this will help.

Also, please rename https_server to esp_https_server.

@MightyPork
Copy link
Contributor Author

it's now rebased again, but i'm trying to fix one new bug I found

@MightyPork
Copy link
Contributor Author

All good, the bug is fixed, close_fn added and I also added license comments. from my side I'm done with this feature, hope it's good like this

* @brief Prototype for freeing context data (if any)
* @param[in] ctx : object to free
*/
typedef void (*httpd_free_sess_ctx_fn_t)(void *ctx);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we have agreed to modify the APIs, I guess we can also rename this to httpd_free_ctx_fn_t since this is being used for both global and session contexts

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, but it'll take about 12 hours before I can do this. If you want, please feel free to rename it yourself

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problem. I'll wait

@anurag-kar
Copy link
Contributor

@MightyPork Except the small changes suggested, this looks really good to me. Thanks for putting all the effort in making this feature possible.

@anurag-kar
Copy link
Contributor

One more thing, please squash your commits into two. One commit for changes to esp_http_server. Second commit adds new esp_https_server component along with examples. This way it looks clean during merge.

Changes:
- renamed `httpd_free_sess_ctx_fn_t` to `httpd_free_ctx_fn_t`
- added a `httpd_handle_t` argument to `httpd_send_func_t` and `httpd_recv_func_t`
- internal function `httpd_sess_get()` is no longer static, as it's used in other
  files besides httpd_sess.c

Bug fixes:
- removed a trailing semicolon from `HTTPD_DEFAULT_CONFIG()`
- fixed issue with failed `select()`, now it automatically closes invalid sockets
  instead of shutting down the entire server

New features:
- `httpd_resp_send()` and `httpd_resp_send_chunk()` now accept -1 as length to use
  `strlen()` internally
- added `httpd_sess_set_ctx()` to accompany `httpd_sess_get_ctx()`
- added a "transport context" to the session structure (next to user context)
- added `httpd_sess_{get,set}_transport_ctx()` to work with this transport context
- added "global user context" and "global transport context" stored in the server
  config (and then the handle); supports a user-provided free_fn
- added a "pending func" to e.g. check for data in the transport layer receive
  buffer
- added functions `httpd_set_sess_{send,recv,pending}_override()` that target
  a session by ID (i.e. not using a request object)
- added `httpd_set_pending_override()`
- added a "open_fn" and "close_fn" - functions called when creating and closing
  a session. These may be used to set up transport layer encryption or some other
  session-wide feature
@MightyPork
Copy link
Contributor Author

@anurag-kar ready for merge and I hope it's now final. The first commit has a detailed message explaining all the changes for future reference

@anurag-kar
Copy link
Contributor

@MightyPork Thank you for cooperating. Will update you when it gets merged internally

@X-Ryl669
Copy link
Contributor

X-Ryl669 commented Nov 5, 2018

Just a question, how if this supposed to working in practice ?
I mean, now the industry is moving to short lived certificates, you'll have a lot of trouble getting a certificate that's valid for, let say, 5 years (even 2 years will be hard in the future). If you make your own certificate, the browser will never accept it and it'll be a pain for user to use such server (they'll have a "security warning" most don't understand, and it's hard to explain to them to add an exception for your certificate). In the end, I guess the only workable way is to have the system somehow, download its certificate from some authority, or have a certbot on the ESP32, but this means always being connected to Internet.

@MightyPork
Copy link
Contributor Author

MightyPork commented Nov 5, 2018 via email

@MightyPork
Copy link
Contributor Author

MightyPork commented Nov 18, 2018

I don't want to sound impatient, but what takes so long about accepting an approved merge request?

@mahavirj
Copy link
Member

@MightyPork

I don't want to sound impatient, but what takes so long about accepting an approved merge request?

Apologies regarding timelines. Approved PR goes through our internal review and testing (functional/integration), so its taking bit longer, in this specific case we also observed few areas for code cleanup. This will reflect in public repository in next few days.

@mahavirj
Copy link
Member

Thanks for contribution. Merged with 61ee1bd

@mahavirj mahavirj closed this Nov 22, 2018
@MightyPork
Copy link
Contributor Author

Thanks for merging and the update!

one mistake i found - https://github.com/espressif/esp-idf/blob/master/docs/en/api-reference/protocols/esp_https_server.rst
this file must be updated to reflect that you renamed all the functions from xxx_sess to sess_xxx (and some of the functions were removed)

(the code changes were done in 9a9d18e)

@mahavirj
Copy link
Member

@MightyPork You are right, we will fix in followup commit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants