2

I'm using openssl library to open a TLS connexion to some server. Reading the library documentation (yes, some people still read documentations and man pages) I stumbled upon the sentence "SSL_libary_init() is not reentrant".

I understand generally speaking what is a non reentrant function: ie some function that keeps an internal state in such a way that calling it twice at the same time or interrupting it while it executes may cause mayhem (the function not doing what callers are expecting).

But in the specific case of SSL_library_init() I wonder what it actually means.

  • does it mean that if some interrupt occurs while calling SSL_library_init() it won't correctly initialize SSL library ? Hence am I supposed to disable all accessible interrupts before calling it and reenable the needed ones aftwerward ?

  • does it means that it's thread unsafe, and that I should ensure that two threads can't call it at the same time ? (looks likely, even if thread safety does not exactly means the same as reentrant).

  • does it means I should'nt call it two times in the program lifetime, or that calling it while SSL connections are open it will wreak havoc ?

AS I'm working on a proxy with one end being client and the other one being server, both ends could potentially be using TLS services, (but i could also be only one end, or none). Should I manage SSL library as a system wide singleton ? If this is the case it's easy enough to manage but it is not exactly a reentracy issue as I understand the word.

I do not know the short word for a function that should only be called once...

I also have a similar question for SSL_CTX_new(). The documentation states it should only be called once per program lifetime. This is annoying as it seems to restrict both server and client (or several independant server or client instances running in the same process) to use the same SSL_METHOD and it does not feel right, but I still hope in this case it's merely some documentation inaccuracy.

Does anyone have enough experience with openSSL to explain what I should or should not do with OpenSSL initialisations code to stay on the safe side ?

Community
  • 1
  • 1
kriss
  • 23,497
  • 17
  • 97
  • 116
  • I don't know SSL, so don't hold me for what I'm saying next, but most commonly when they say "this function is not re-entrant", they say so because they access some global variable. Since it's an _init_ function, it makes sense to just call it once in `main` and be done with it (so you wouldn't care about thread-safety or re-entrant-ness!). `SSL_CTX_new` also sounds like it initializes global variables, so calling it multiple times doesn't achieve anything (except memory leak perhaps). Again, I don't know SSL, so these are all just guesses. – Shahbaz Mar 28 '13 at 16:55
  • @Shahbaz: yes, you are probably right. Not much to do with reentrancy but it's probably what it means. The second one is is more annoying if it's actually gloabl, because it sets some dispatch table (but I still hope it won't really be global: if it where why should it allocate memory ? – kriss Mar 28 '13 at 17:14
  • again, I have no idea what SSL is, but looking at the documentation of [SSL_CTX_new](http://www.openssl.org/docs/ssl/SSL_CTX_new.html), I don't see any mention of "having to be called only once per program lifetime". Where did you see that? – Shahbaz Mar 28 '13 at 17:39
  • `SSL_CTX (SSL Context): That's the global context structure which is created by a server or client *once per program life-time* and which holds mainly default values for the SSL structures which are later created for the connections.` – kriss Mar 29 '13 at 08:59
  • I just hope it means that it must be called at least one time per program. If it means once and only once that's a problem because then all the open SSL connections will have to use the same protocol level (dispatch table SSL_METHOD). – kriss Mar 29 '13 at 09:01
  • I see. Actually, since it returns an `SSL_CTX *`, I suspect that it's ok if you call it multiple times; You'll get multiple contexts. It says once per program life-time probably because they didn't suspect anyone would want to have multiple contexts in the same program, so they say one is enough (not that more is harmful). You may get a better idea if you ask in their mailing list (if they have one) or look at the source code. – Shahbaz Mar 29 '13 at 10:33

1 Answers1

1

I can give you a hint based on what I'm seeing. I have a CentOS 7 / Django 1.9.3 / Apache 2.4 / mod_ssl / Python 3.4 web server that receives https: connections from users. While processing requests, the server needs to query a backend for information needed to satisfy the request. The backend query works fine when run standalone, but it generates:

OSError(0, 'Error')
Line 810, /lib64/python3.4/ssl.py

803  def do_handshake(self, block=False):
804      """Perform a TLS/SSL handshake."""
805      self._check_connected()
806      timeout = self.gettimeout()
807      try:
808          if timeout == 0.0 and block:
809              self.settimeout(None)
810          self._sslobj.do_handshake()          # <<<-------

when run in the Apache WSGI context.

If in fact mod_ssl is causing my error, that implies that the library is thread safe (because Apache of course can serve multiple web requests concurrently) but non-reentrant (because SSL cannot be used twice -- e.g. for front-end and back-end connections -- in a single thread).

Surely two-tier web servers are a mature design pattern so there must be a workaround. Thanks for posting that bit about non-reentrancy - it was the first clue I've found that might be the cause of my problem.

For reference, my code calls a RESTful service that takes the user's distinguished name extracted from SSL_CLIENT_CERT and returns user attributes in JSON format:

import requests, urllib

URL = 'https://example.com/rest/user_info/'

def get_user_info(dn)
    query = URL + urllib.parse.quote(dn)
    return requests.get(query, cert=('server.crt', 'server.key'), verify='ca_bundle.crt').json()

That code works perfectly when run from the command line on the web server (in the WSGI directory as user apache) but blows up when invoked by Apache itself.

Dave
  • 3,834
  • 2
  • 29
  • 44