OpenSSL with nonblocking sockets in Perl (devpit.org)

SSL/TLS is complete chaos with little documentation. OpenSSL is a huge library. It has tons of functionality, and has some reasonable documentation, but gives you no idea where to start. Perl has, as usual, lots of modules and few to the point. Net::SSLeay seems to be Perl's raw canonical wrapper for OpenSSL, although if I hadn't told you, you'd have to examine a dozen modules with similar names before you came to this conclusion.

The hardest part, as usual, is getting started and figuring out the general framework. Specifics are actually pretty well documented by OpenSSL, although you have to guess at how the C translates through Net::SSLeay into Perl. The critical elements of Net::SSLeay are in some examples that are hard to read and bug-ridden to boot. Try guessing by looking for patterns defined by the parts of the interface you already know; this is not easy, but may be your only option. OpenSSL exports two key object types for dealing with SSL. They are SSL_CTX (the "context" object) and SSL. Usually you only want one SSL_CTX object and several SSL objects. SSL_CTX holds your local certificate if you're writing a server.

I need to make the poor quality of Net::SSLeay abundantly clear. OpenSSL is robust, but you need to carefully pick and choose and inspect what you use from Net::SSLeay. Needless to say, we'd like to be able to write very robust software that doesn't sometimes fail or act strangely. Be careful; Net::SSLeay is riddled with bugs. For the most part, I use it only to import raw OpenSSL interfaces and avoid anything written in Net::SSLeay that's written in native Perl because it's so bug-ridden. For example, let's look at ssl_write_CRLF, which by name sounds like a central element. Its contents is simply:

return ssl_write_all($_[0], $_[1]) + ssl_write_all($_[0], $CRLF);

Well, what if ssl_write_all() returns undef because of an error on the first call but not the second? First off, your code should emit an uninitialized warning (you do use warnings, and pay attention to them, right?) but Net::SSLeay doesn't use warnings, so you won't even know something is fishy. Second, your code will have written a blank line and silently discarded the important information. I think this is a problem! There are many similar bugs; I'd report them, but the upshot is that Net::SSLeay was simply written without care and my bug reports would turn into a rewrite. Generally the most common code path works, but god help you with nonblocking IO, where read and write calls "fail" intermittently to avoid blocking. Stick with the raw OpenSSL functions that Net::SSLeay will load for you (they work well). You can tell the difference because the raw OpenSSL functions do not appear in Net/SSLeay.pm.

After exploring this chaos for some time, I gleaned the critical elements for using nonblocking IO with SSL in Perl. I wrote some code that shows exactly what needs to be done, complete with error reporting and the appropriate retries. This is a trivial web server. Run it, and visit https://localhost:8888/ and your browser should show a copy of /usr/share/games/fortune/fortunes. The debugging output may help you trace execution if you get lost in the looping for reading and writing.

See the example attached below.

Attachments

Story URL: 

Comments

Post new comment

The content of this field is kept private and will not be shown publicly.
To prevent automated spam submissions leave this field empty.