Libcrypto API

From OpenSSLWiki
Revision as of 03:30, 10 December 2014 by Ruslan (talk | contribs) (→‎Getting Started: missing include in the first example)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigationJump to search

OpenSSL provides two primary libraries: libssl and libcrypto. The libcrypto library provides the fundamental cryptographic routines used by libssl. You can however use libcrypto without using libssl.

Getting Started

In order to use libcrypto it must first (typically) be initialised:

#include <openssl/conf.h>
#include <openssl/evp.h>
#include <openssl/err.h>

int main(int arc, char *argv[])
{ 
  /* Load the human readable error strings for libcrypto */
  ERR_load_crypto_strings();

  /* Load all digest and cipher algorithms */
  OpenSSL_add_all_algorithms();

  /* Load config file, and other important initialisation */
  OPENSSL_config(NULL);

  /* ... Do some crypto stuff here ... */

  /* Clean up */

  /* Removes all digests and ciphers */
  EVP_cleanup();

  /* if you omit the next, a small leak may be left when you make use of the BIO (low level API) for e.g. base64 transformations */
  CRYPTO_cleanup_all_ex_data();

  /* Remove error strings */
  ERR_free_strings();

  return 0;
}

High Level and Low Level Interfaces

For most uses, users should use the high level interface that is provided for performing cryptographic operations. This is known as the EVP interface (short for Envelope). This interface provides a suite of functions for performing encryption/decryption (both symmetric and asymmetric), signing/verifying, as well as generating hashes and MAC codes, across the full range of OpenSSL supported algorithms and modes. Working with the high level interface means that a lot of the complexity of performing cryptographic operations is hidden from view. A single consistent API is provided. In the event that you need to change your code to use a different algorithm (for example), then this is a simple change when using the high level interface. In addition low level issues such as padding and encryption modes are all handled for you.

Refer to EVP for further information on the high level interface.

In addition to the high level interface, OpenSSL also provides low level interfaces for working directly with the individual algorithms. These low level interfaces are not recommended for the novice user, but provide a degree of control that may not be possible when using only the high level interface. Note that many low-level interfaces are not available if you are running in FIPS mode.

Error Handling

Most OpenSSL functions will return an integer to indicate success or failure. Typically a function will return 1 on success or 0 on error. All return codes should be checked and handled as appropriate.

It is common to see errors handled in a way similar to the following:

  if(1 != EVP_xxx()) goto err;
  if(1 != EVP_yyy()) goto err;

  /* ... do some stuff ... */

err:
  ERR_print_errors_fp(stderr);

Note that not all of the libcrypto functions return 0 for error and 1 for success. There are exceptions which can trip up the unwary. For example if you want to check a signature with some functions you get 1 if the signature is correct, 0 if it is not correct and -1 if something bad happened like a memory allocation failure. So if you do:

 if (some_verify_function())
    /* signature successful */

and someone can induce the "something bad happened" condition you end up behaving as though a bad signature is good. This one cropped up in the library internals at one point and was fixed in a security release. Currently you should check the manual pages or the source to be sure.

One way to avoid being bitten by this potential problem is to always use this idiom to check for errors when calling an OpenSSL function:

 if (1 != some_openssl_function())
    /* handle error */

Refer to the Library Errors page for more information about OpenSSL errors.

Thread Safety

OpenSSL currently is thread-NOT-safe by default. In order to make it thread-safe the caller has to provide various callbacks for locking, atomic integer addition, and thread ID determination (this last has reasonable defaults). This makes it difficult to use OpenSSL from multiple distinct objects in one multi-threaded process: one of them had better provide these callbacks, but only one of them should.

Currently the only moderately safe way for libraries using OpenSSL to handle thread safety is to do the following as early as possible, possible in .init or DllMain:

  • Check if the locking callback has been set, then set it if not;
  • CRYPTO_w_lock(CRYPTO_LOCK_DYNLOCK), set the remaining callbacks (threadid, dynlock, and add_lock) if not already set, then CRYPTO_w_unlock(CRYPTO_LOCK_DYNLOCK);

In the future we hope that OpenSSL will self-initialize thread-safely to use native threading where available.

Fork Safety

main article: Random fork-safety

OpenSSL library functions are generally not async-signal-safe, therefore:

  • do not call OpenSSL functions from signal handlers
  • do not call OpenSSL functions on the child-side of fork() (exec or _exit)
  • do not call OpenSSL functions from pthread_atfork() handlers (fork() itself is and must be and remain async-signal-safe)

If you have an application for which using OpenSSL on the parent and child sides of fork() (without exec'ing) and it does not blow up naturally, then you should arrange to call RAND_poll() on the child-side of fork() before using any other RAND functions.

Further libcrypto information

There are a number of other pages that cover specific aspects of working with libcrypto:

See also