Talk:Libcrypto API

From OpenSSLWiki
Revision as of 04:33, 4 March 2013 by Ppelleti (talk | contribs) (Initialization and engines?)

Jump to: navigation, search

Initialization and engines?

Should the recommended initialization code include a call to ENGINE_load_builtin_engines? (Or to OPENSSL_config, which calls ENGINE_load_builtin_engines.) Otherwise, the RdRand engine for getting better random numbers from newer Intel chips (as one example) won't be used.

(My own thoughts on OpenSSL initialization are here.)

--Ppelleti 18:05, 3 March 2013 (UTC)

Hmmm - I've not come across this as a recommendation before. What is the original source for your recommendation?

--Matt 22:15, 3 March 2013 (UTC)

It's not from any existing documentation source, other than gleaning some information from the engine manpage (see "Automatically using builtin ENGINE implementations") and the CHANGES file. But mostly it's my own conclusion, based on reading the source code and performing experiments.

The basic question I was trying to answer was, on modern Intel processors which support AES-NI and RdRand, is OpenSSL taking advantage of these hardware features. The answer appears to be different for the two different features. For AES-NI, it appears from the source code (and was recently confirmed on the mailing list) that AES-NI is automatically used if it is available, without needing to do anything special.

However, for RdRand, it appears that the answer is different. In the source code, there is a separate RdRand engine. If the RdRand engine is not used, then the default pool implementation in md_rand.c is used, and you don't get the benefits of RdRand.

From the section I already mentioned in the "engine" manpage, it sounded like no engines are used by default, and you must enable them by calling ENGINE_load_builtin_engines() followed by ENGINE_register_all_complete(). Although the CHANGES file partially contradicts this advice, saying:

  *) Add call to ENGINE_register_all_complete() to
     ENGINE_load_builtin_engines(), so some implementations get used
     automatically instead of needing explicit application support.
     [Steve Henson]

I did some experiments on a machine with RdRand. I wrote the following little bit of code:

  ENGINE *rnd = ENGINE_get_default_RAND ();
  if (rnd)
    printf ("default rand engine: %s\n", ENGINE_get_name (rnd));
    printf ("no default rand engine\n");

If I initialize OpenSSL the typical way:

  SSL_load_error_strings();                /* readable error messages */
  SSL_library_init();                      /* initialize library */

without calling any ENGINE functions, then my little code fragment will print "no default rand engine", indicating the implementation from md_rand.c is being used. But if I call ENGINE_load_builtin_engines() after the other initialization functions, and before my little test, it then prints out that RdRand is the default rand engine.

So, this is how I drew the conclusion that it's necessary to call ENGINE_load_builtin_engines() as part of your initialization, if you want to get RdRand support.

However, this is all made a little bit trickier by the fact that OpenSSL_add_all_algorithms() can actually mean one of two vastly different things, depending on a #define at compile time. If OPENSSL_LOAD_CONF is defined, then OpenSSL_add_all_algorithms() is really OPENSSL_add_all_algorithms_conf(), but if OPENSSL_LOAD_CONF is not defined (which is the default), then OpenSSL_add_all_algorithms() is really OPENSSL_add_all_algorithms_noconf().

OPENSSL_add_all_algorithms_conf() is a two-line function:

void OPENSSL_add_all_algorithms_conf(void)

So the difference is that if OPENSSL_LOAD_CONF is defined, then OPENSSL_config() is called, when it otherwise wouldn't be. What does this have to do with RdRand? The thing is that OPENSSL_config() calls ENGINE_load_builtin_engines(). (And then ENGINE_load_builtin_engines() in turn calls ENGINE_register_all_complete(), as mentioned in the CHANGES entry.)

So, to get RdRand support, you can either #define OPENSSL_LOAD_CONF when building your program, or you can call either ENGINE_load_builtin_engines() or OPENSSL_config() in your initialization sequence. However, it appears that calling ENGINE_load_builtin_engines() more than once will leak memory, so ideally you don't want to call ENGINE_load_builtin_engines() if you also plan on calling OPENSSL_config(), or if you've defined OPENSSL_LOAD_CONF. (Of course, since it's just a small fixed-size leak at initialization, this wouldn't really be a practical problem, but still makes me feel icky.)

--Ppelleti 04:33, 4 March 2013 (UTC)

Best practices for printing errors

I'm curious about the recommendation to do this:

   unsigned long errCode;
   while(errCode = ERR_get_error())
     char *err = ERR_error_string(errCode, NULL);
     printf("%s\n", err);

Wouldn't it be much simpler to just do:


Or, if one really does want to iterate through each line of the error queue individually, wouldn't it still be better for us to recommend using ERR_error_string_n with an explicit buffer? ERR_error_string with a NULL argument is not thread-safe.

--Ppelleti 18:12, 3 March 2013 (UTC)

Either way does the trick, but I agree yours is simpler. I'll change it.,

--Matt 22:16, 3 March 2013 (UTC)