/* * OpenVPN -- An application to securely tunnel IP networks * over a single TCP/UDP port, with support for SSL/TLS-based * session authentication and key exchange, * packet encryption, packet authentication, and * packet compression. * * Copyright (C) 2002-2008 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program (see the file COPYING included with this * distribution); if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "syshead.h" #ifdef USE_CRYPTO #include "crypto.h" #include "error.h" #include "misc.h" #include "thread.h" #include "memdbg.h" /* * Check for key size creepage. */ #if MAX_CIPHER_KEY_LENGTH < EVP_MAX_KEY_LENGTH #warning Some OpenSSL EVP ciphers now support key lengths greater than MAX_CIPHER_KEY_LENGTH -- consider increasing MAX_CIPHER_KEY_LENGTH #endif #if MAX_HMAC_KEY_LENGTH < EVP_MAX_MD_SIZE #warning Some OpenSSL HMAC message digests now support key lengths greater than MAX_HMAC_KEY_LENGTH -- consider increasing MAX_HMAC_KEY_LENGTH #endif /* * Encryption and Compression Routines. * * On entry, buf contains the input data and length. * On exit, it should be set to the output data and length. * * If buf->len is <= 0 we should return * If buf->len is set to 0 on exit it tells the caller to ignore the packet. * * work is a workspace buffer we are given of size BUF_SIZE. * work may be used to return output data, or the input buffer * may be modified and returned as output. If output data is * returned in work, the data should start after FRAME_HEADROOM bytes * of padding to leave room for downstream routines to prepend. * * Up to a total of FRAME_HEADROOM bytes may be prepended to the input buf * by all routines (encryption, decryption, compression, and decompression). * * Note that the buf_prepend return will assert if we try to * make a header bigger than FRAME_HEADROOM. This should not * happen unless the frame parameters are wrong. */ #define CRYPT_ERROR(format) \ do { msg (D_CRYPT_ERRORS, "%s: " format, error_prefix); goto error_exit; } while (false) void openvpn_encrypt (struct buffer *buf, struct buffer work, const struct crypto_options *opt, const struct frame* frame) { struct gc_arena gc; gc_init (&gc); if (buf->len > 0 && opt->key_ctx_bi) { struct key_ctx *ctx = &opt->key_ctx_bi->encrypt; /* Do Encrypt from buf -> work */ if (ctx->cipher) { uint8_t iv_buf[EVP_MAX_IV_LENGTH]; const int iv_size = EVP_CIPHER_CTX_iv_length (ctx->cipher); const unsigned int mode = EVP_CIPHER_CTX_mode (ctx->cipher); int outlen; if (mode == EVP_CIPH_CBC_MODE) { CLEAR (iv_buf); /* generate pseudo-random IV */ if (opt->flags & CO_USE_IV) prng_bytes (iv_buf, iv_size); /* Put packet ID in plaintext buffer or IV, depending on cipher mode */ if (opt->packet_id) { struct packet_id_net pin; packet_id_alloc_outgoing (&opt->packet_id->send, &pin, BOOL_CAST (opt->flags & CO_PACKET_ID_LONG_FORM)); ASSERT (packet_id_write (&pin, buf, BOOL_CAST (opt->flags & CO_PACKET_ID_LONG_FORM), true)); } } else if (mode == EVP_CIPH_CFB_MODE || mode == EVP_CIPH_OFB_MODE) { struct packet_id_net pin; struct buffer b; ASSERT (opt->flags & CO_USE_IV); /* IV and packet-ID required */ ASSERT (opt->packet_id); /* for this mode. */ packet_id_alloc_outgoing (&opt->packet_id->send, &pin, true); memset (iv_buf, 0, iv_size); buf_set_write (&b, iv_buf, iv_size); ASSERT (packet_id_write (&pin, &b, true, false)); } else /* We only support CBC, CFB, or OFB modes right now */ { ASSERT (0); } /* initialize work buffer with FRAME_HEADROOM bytes of prepend capacity */ ASSERT (buf_init (&work, FRAME_HEADROOM (frame))); /* set the IV pseudo-randomly */ if (opt->flags & CO_USE_IV) dmsg (D_PACKET_CONTENT, "ENCRYPT IV: %s", format_hex (iv_buf, iv_size, 0, &gc)); dmsg (D_PACKET_CONTENT, "ENCRYPT FROM: %s", format_hex (BPTR (buf), BLEN (buf), 80, &gc)); /* cipher_ctx was already initialized with key & keylen */ ASSERT (EVP_CipherInit_ov (ctx->cipher, NULL, NULL, iv_buf, DO_ENCRYPT)); /* Buffer overflow check */ if (!buf_safe (&work, buf->len + EVP_CIPHER_CTX_block_size (ctx->cipher))) { msg (D_CRYPT_ERRORS, "ENCRYPT: buffer size error, bc=%d bo=%d bl=%d wc=%d wo=%d wl=%d cbs=%d", buf->capacity, buf->offset, buf->len, work.capacity, work.offset, work.len, EVP_CIPHER_CTX_block_size (ctx->cipher)); goto err; } /* Encrypt packet ID, payload */ ASSERT (EVP_CipherUpdate_ov (ctx->cipher, BPTR (&work), &outlen, BPTR (buf), BLEN (buf))); work.len += outlen; /* Flush the encryption buffer */ ASSERT (EVP_CipherFinal (ctx->cipher, BPTR (&work) + outlen, &outlen)); work.len += outlen; ASSERT (outlen == iv_size); /* prepend the IV to the ciphertext */ if (opt->flags & CO_USE_IV) { uint8_t *output = buf_prepend (&work, iv_size); ASSERT (output); memcpy (output, iv_buf, iv_size); } dmsg (D_PACKET_CONTENT, "ENCRYPT TO: %s", format_hex (BPTR (&work), BLEN (&work), 80, &gc)); } else /* No Encryption */ { if (opt->packet_id) { struct packet_id_net pin; packet_id_alloc_outgoing (&opt->packet_id->send, &pin, BOOL_CAST (opt->flags & CO_PACKET_ID_LONG_FORM)); ASSERT (packet_id_write (&pin, buf, BOOL_CAST (opt->flags & CO_PACKET_ID_LONG_FORM), true)); } work = *buf; } /* HMAC the ciphertext (or plaintext if !cipher) */ if (ctx->hmac) { int hmac_len; uint8_t *output; HMAC_Init_ex (ctx->hmac, NULL, 0, NULL, NULL); HMAC_Update (ctx->hmac, BPTR (&work), BLEN (&work)); output = buf_prepend (&work, HMAC_size (ctx->hmac)); ASSERT (output); HMAC_Final (ctx->hmac, output, (unsigned int *)&hmac_len); ASSERT (hmac_len == HMAC_size (ctx->hmac)); } *buf = work; } gc_free (&gc); return; err: ERR_clear_error (); buf->len = 0; gc_free (&gc); return; } /* * If (opt->flags & CO_USE_IV) is not NULL, we will read an IV from the packet. * * Set buf->len to 0 and return false on decrypt error. * * On success, buf is set to point to plaintext, true * is returned. */ bool openvpn_decrypt (struct buffer *buf, struct buffer work, const struct crypto_options *opt, const struct frame* frame) { static const char error_prefix[] = "Authenticate/Decrypt packet error"; struct gc_arena gc; gc_init (&gc); if (buf->len > 0 && opt->key_ctx_bi) { struct key_ctx *ctx = &opt->key_ctx_bi->decrypt; struct packet_id_net pin; bool have_pin = false; /* Verify the HMAC */ if (ctx->hmac) { int hmac_len; uint8_t local_hmac[MAX_HMAC_KEY_LENGTH]; /* HMAC of ciphertext computed locally */ int in_hmac_len; HMAC_Init_ex (ctx->hmac, NULL, 0, NULL, NULL); /* Assume the length of the input HMAC */ hmac_len = HMAC_size (ctx->hmac); /* Authentication fails if insufficient data in packet for HMAC */ if (buf->len < hmac_len) CRYPT_ERROR ("missing authentication info"); HMAC_Update (ctx->hmac, BPTR (buf) + hmac_len, BLEN (buf) - hmac_len); HMAC_Final (ctx->hmac, local_hmac, (unsigned int *)&in_hmac_len); ASSERT (hmac_len == in_hmac_len); /* Compare locally computed HMAC with packet HMAC */ if (memcmp (local_hmac, BPTR (buf), hmac_len)) CRYPT_ERROR ("packet HMAC authentication failed"); ASSERT (buf_advance (buf, hmac_len)); } /* Decrypt packet ID + payload */ if (ctx->cipher) { const unsigned int mode = EVP_CIPHER_CTX_mode (ctx->cipher); const int iv_size = EVP_CIPHER_CTX_iv_length (ctx->cipher); uint8_t iv_buf[EVP_MAX_IV_LENGTH]; int outlen; /* initialize work buffer with FRAME_HEADROOM bytes of prepend capacity */ ASSERT (buf_init (&work, FRAME_HEADROOM_ADJ (frame, FRAME_HEADROOM_MARKER_DECRYPT))); /* use IV if user requested it */ CLEAR (iv_buf); if (opt->flags & CO_USE_IV) { if (buf->len < iv_size) CRYPT_ERROR ("missing IV info"); memcpy (iv_buf, BPTR (buf), iv_size); ASSERT (buf_advance (buf, iv_size)); } /* show the IV's initial state */ if (opt->flags & CO_USE_IV) dmsg (D_PACKET_CONTENT, "DECRYPT IV: %s", format_hex (iv_buf, iv_size, 0, &gc)); if (buf->len < 1) CRYPT_ERROR ("missing payload"); /* ctx->cipher was already initialized with key & keylen */ if (!EVP_CipherInit_ov (ctx->cipher, NULL, NULL, iv_buf, DO_DECRYPT)) CRYPT_ERROR ("cipher init failed"); /* Buffer overflow check (should never happen) */ if (!buf_safe (&work, buf->len)) CRYPT_ERROR ("buffer overflow"); /* Decrypt packet ID, payload */ if (!EVP_CipherUpdate_ov (ctx->cipher, BPTR (&work), &outlen, BPTR (buf), BLEN (buf))) CRYPT_ERROR ("cipher update failed"); work.len += outlen; /* Flush the decryption buffer */ if (!EVP_CipherFinal (ctx->cipher, BPTR (&work) + outlen, &outlen)) CRYPT_ERROR ("cipher final failed"); work.len += outlen; dmsg (D_PACKET_CONTENT, "DECRYPT TO: %s", format_hex (BPTR (&work), BLEN (&work), 80, &gc)); /* Get packet ID from plaintext buffer or IV, depending on cipher mode */ { if (mode == EVP_CIPH_CBC_MODE) { if (opt->packet_id) { if (!packet_id_read (&pin, &work, BOOL_CAST (opt->flags & CO_PACKET_ID_LONG_FORM))) CRYPT_ERROR ("error reading CBC packet-id"); have_pin = true; } } else if (mode == EVP_CIPH_CFB_MODE || mode == EVP_CIPH_OFB_MODE) { struct buffer b; ASSERT (opt->flags & CO_USE_IV); /* IV and packet-ID required */ ASSERT (opt->packet_id); /* for this mode. */ buf_set_read (&b, iv_buf, iv_size); if (!packet_id_read (&pin, &b, true)) CRYPT_ERROR ("error reading CFB/OFB packet-id"); have_pin = true; } else /* We only support CBC, CFB, or OFB modes right now */ { ASSERT (0); } } } else { work = *buf; if (opt->packet_id) { if (!packet_id_read (&pin, &work, BOOL_CAST (opt->flags & CO_PACKET_ID_LONG_FORM))) CRYPT_ERROR ("error reading packet-id"); have_pin = !BOOL_CAST (opt->flags & CO_IGNORE_PACKET_ID); } } if (have_pin) { packet_id_reap_test (&opt->packet_id->rec); if (packet_id_test (&opt->packet_id->rec, &pin)) { packet_id_add (&opt->packet_id->rec, &pin); if (opt->pid_persist && (opt->flags & CO_PACKET_ID_LONG_FORM)) packet_id_persist_save_obj (opt->pid_persist, opt->packet_id); } else { if (!(opt->flags & CO_MUTE_REPLAY_WARNINGS)) msg (D_REPLAY_ERRORS, "%s: bad packet ID (may be a replay): %s -- see the man page entry for --no-replay and --replay-window for more info or silence this warning with --mute-replay-warnings", error_prefix, packet_id_net_print (&pin, true, &gc)); goto error_exit; } } *buf = work; } gc_free (&gc); return true; error_exit: ERR_clear_error (); buf->len = 0; gc_free (&gc); return false; } /* * How many bytes will we add to frame buffer for a given * set of crypto options? */ void crypto_adjust_frame_parameters(struct frame *frame, const struct key_type* kt, bool cipher_defined, bool use_iv, bool packet_id, bool packet_id_long_form) { frame_add_to_extra_frame (frame, (packet_id ? packet_id_size (packet_id_long_form) : 0) + ((cipher_defined && use_iv) ? EVP_CIPHER_iv_length (kt->cipher) : 0) + (cipher_defined ? EVP_CIPHER_block_size (kt->cipher) : 0) + /* worst case padding expansion */ kt->hmac_length); } static const EVP_CIPHER * get_cipher (const char *ciphername) { const EVP_CIPHER *cipher = NULL; ASSERT (ciphername); cipher = EVP_get_cipherbyname (ciphername); if ( !(cipher && cipher_ok (OBJ_nid2sn (EVP_CIPHER_nid (cipher))))) msg (M_SSLERR, "Cipher algorithm '%s' not found", ciphername); if (EVP_CIPHER_key_length (cipher) > MAX_CIPHER_KEY_LENGTH) msg (M_FATAL, "Cipher algorithm '%s' uses a default key size (%d bytes) which is larger than " PACKAGE_NAME "'s current maximum key size (%d bytes)", ciphername, EVP_CIPHER_key_length (cipher), MAX_CIPHER_KEY_LENGTH); return cipher; } static const EVP_MD * get_md (const char *digest) { const EVP_MD *md = NULL; ASSERT (digest); md = EVP_get_digestbyname (digest); if (!md) msg (M_SSLERR, "Message hash algorithm '%s' not found", digest); if (EVP_MD_size (md) > MAX_HMAC_KEY_LENGTH) msg (M_FATAL, "Message hash algorithm '%s' uses a default hash size (%d bytes) which is larger than " PACKAGE_NAME "'s current maximum hash size (%d bytes)", digest, EVP_MD_size (md), MAX_HMAC_KEY_LENGTH); return md; } static void init_cipher (EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, struct key *key, const struct key_type *kt, int enc, const char *prefix) { struct gc_arena gc = gc_new (); EVP_CIPHER_CTX_init (ctx); if (!EVP_CipherInit_ov (ctx, cipher, NULL, NULL, enc)) msg (M_SSLERR, "EVP cipher init #1"); #ifdef HAVE_EVP_CIPHER_CTX_SET_KEY_LENGTH if (!EVP_CIPHER_CTX_set_key_length (ctx, kt->cipher_length)) msg (M_SSLERR, "EVP set key size"); #endif if (!EVP_CipherInit_ov (ctx, NULL, key->cipher, NULL, enc)) msg (M_SSLERR, "EVP cipher init #2"); msg (D_HANDSHAKE, "%s: Cipher '%s' initialized with %d bit key", prefix, OBJ_nid2sn (EVP_CIPHER_CTX_nid (ctx)), EVP_CIPHER_CTX_key_length (ctx) * 8); /* make sure we used a big enough key */ ASSERT (EVP_CIPHER_CTX_key_length (ctx) <= kt->cipher_length); dmsg (D_SHOW_KEYS, "%s: CIPHER KEY: %s", prefix, format_hex (key->cipher, kt->cipher_length, 0, &gc)); dmsg (D_CRYPTO_DEBUG, "%s: CIPHER block_size=%d iv_size=%d", prefix, EVP_CIPHER_CTX_block_size (ctx), EVP_CIPHER_CTX_iv_length (ctx)); gc_free (&gc); } static void init_hmac (HMAC_CTX *ctx, const EVP_MD *digest, struct key *key, const struct key_type *kt, const char *prefix) { struct gc_arena gc = gc_new (); HMAC_CTX_init (ctx); HMAC_Init_ex (ctx, key->hmac, kt->hmac_length, digest, NULL); msg (D_HANDSHAKE, "%s: Using %d bit message hash '%s' for HMAC authentication", prefix, HMAC_size (ctx) * 8, OBJ_nid2sn (EVP_MD_type (digest))); /* make sure we used a big enough key */ ASSERT (HMAC_size (ctx) <= kt->hmac_length); dmsg (D_SHOW_KEYS, "%s: HMAC KEY: %s", prefix, format_hex (key->hmac, kt->hmac_length, 0, &gc)); dmsg (D_CRYPTO_DEBUG, "%s: HMAC size=%d block_size=%d", prefix, EVP_MD_size (digest), EVP_MD_block_size (digest)); gc_free (&gc); } /* * Build a struct key_type. */ void init_key_type (struct key_type *kt, const char *ciphername, bool ciphername_defined, const char *authname, bool authname_defined, int keysize, bool cfb_ofb_allowed, bool warn) { CLEAR (*kt); if (ciphername && ciphername_defined) { kt->cipher = get_cipher (ciphername); kt->cipher_length = EVP_CIPHER_key_length (kt->cipher); if (keysize > 0 && keysize <= MAX_CIPHER_KEY_LENGTH) kt->cipher_length = keysize; /* check legal cipher mode */ { const unsigned int mode = EVP_CIPHER_mode (kt->cipher); if (!(mode == EVP_CIPH_CBC_MODE #ifdef ALLOW_NON_CBC_CIPHERS || (cfb_ofb_allowed && (mode == EVP_CIPH_CFB_MODE || mode == EVP_CIPH_OFB_MODE)) #endif )) #ifdef ENABLE_SMALL msg (M_FATAL, "Cipher '%s' mode not supported", ciphername); #else msg (M_FATAL, "Cipher '%s' uses a mode not supported by " PACKAGE_NAME " in your current configuration. CBC mode is always supported, while CFB and OFB modes are supported only when using SSL/TLS authentication and key exchange mode, and when " PACKAGE_NAME " has been built with ALLOW_NON_CBC_CIPHERS.", ciphername); #endif } } else { if (warn) msg (M_WARN, "******* WARNING *******: null cipher specified, no encryption will be used"); } if (authname && authname_defined) { kt->digest = get_md (authname); kt->hmac_length = EVP_MD_size (kt->digest); } else { if (warn) msg (M_WARN, "******* WARNING *******: null MAC specified, no authentication will be used"); } } const char * kt_cipher_name (const struct key_type *kt) { if (kt->cipher) return EVP_CIPHER_name (kt->cipher); else return "[null-cipher]"; } const char * kt_digest_name (const struct key_type *kt) { if (kt->digest) return EVP_MD_name (kt->digest); else return "[null-digest]"; } int kt_key_size (const struct key_type *kt) { if (kt->cipher_length) return kt->cipher_length * 8; else if (kt->cipher) return EVP_CIPHER_key_length (kt->cipher) * 8; else return 0; } /* given a key and key_type, build a key_ctx */ void init_key_ctx (struct key_ctx *ctx, struct key *key, const struct key_type *kt, int enc, const char *prefix) { CLEAR (*ctx); if (kt->cipher && kt->cipher_length > 0) { ALLOC_OBJ (ctx->cipher, EVP_CIPHER_CTX); init_cipher (ctx->cipher, kt->cipher, key, kt, enc, prefix); } if (kt->digest && kt->hmac_length > 0) { ALLOC_OBJ (ctx->hmac, HMAC_CTX); init_hmac (ctx->hmac, kt->digest, key, kt, prefix); } } void free_key_ctx (struct key_ctx *ctx) { if (ctx->cipher) { EVP_CIPHER_CTX_cleanup (ctx->cipher); free (ctx->cipher); ctx->cipher = NULL; } if (ctx->hmac) { HMAC_CTX_cleanup (ctx->hmac); free (ctx->hmac); ctx->hmac = NULL; } } void free_key_ctx_bi (struct key_ctx_bi *ctx) { free_key_ctx(&ctx->encrypt); free_key_ctx(&ctx->decrypt); } /* * Return number of DES cblocks for the current * key type or 0 if not a DES cipher. */ static int n_DES_cblocks (const struct key_type *kt) { int ret = 0; const char *name = OBJ_nid2sn (EVP_CIPHER_nid (kt->cipher)); if (name) { if (!strncmp (name, "DES-", 4)) { ret = EVP_CIPHER_key_length (kt->cipher) / sizeof (DES_cblock); } else if (!strncmp (name, "DESX-", 5)) { ret = 1; } } dmsg (D_CRYPTO_DEBUG, "CRYPTO INFO: n_DES_cblocks=%d", ret); return ret; } static bool check_key_DES (struct key *key, const struct key_type *kt, int ndc) { int i; struct buffer b; buf_set_read (&b, key->cipher, kt->cipher_length); for (i = 0; i < ndc; ++i) { DES_cblock *dc = (DES_cblock*) buf_read_alloc (&b, sizeof (DES_cblock)); if (!dc) { msg (D_CRYPT_ERRORS, "CRYPTO INFO: check_key_DES: insufficient key material"); goto err; } if (DES_is_weak_key(dc)) { msg (D_CRYPT_ERRORS, "CRYPTO INFO: check_key_DES: weak key detected"); goto err; } if (!DES_check_key_parity (dc)) { msg (D_CRYPT_ERRORS, "CRYPTO INFO: check_key_DES: bad parity detected"); goto err; } } return true; err: ERR_clear_error (); return false; } static void fixup_key_DES (struct key *key, const struct key_type *kt, int ndc) { int i; struct buffer b; buf_set_read (&b, key->cipher, kt->cipher_length); for (i = 0; i < ndc; ++i) { DES_cblock *dc = (DES_cblock*) buf_read_alloc(&b, sizeof(DES_cblock)); if (!dc) { msg (D_CRYPT_ERRORS, "CRYPTO INFO: fixup_key_DES: insufficient key material"); ERR_clear_error (); return; } DES_set_odd_parity (dc); } } static bool key_is_zero (struct key *key, const struct key_type *kt) { int i; for (i = 0; i < kt->cipher_length; ++i) if (key->cipher[i]) return false; msg (D_CRYPT_ERRORS, "CRYPTO INFO: WARNING: zero key detected"); return true; } /* * Make sure that cipher key is a valid key for current key_type. */ bool check_key (struct key *key, const struct key_type *kt) { if (kt->cipher) { /* * Check for zero key */ if (key_is_zero(key, kt)) return false; /* * Check for weak or semi-weak DES keys. */ { const int ndc = n_DES_cblocks (kt); if (ndc) return check_key_DES (key, kt, ndc); else return true; } } return true; } /* * Make safe mutations to key to ensure it is valid, * such as ensuring correct parity on DES keys. * * This routine cannot guarantee it will generate a good * key. You must always call check_key after this routine * to make sure. */ void fixup_key (struct key *key, const struct key_type *kt) { struct gc_arena gc = gc_new (); if (kt->cipher) { #ifdef ENABLE_DEBUG const struct key orig = *key; #endif const int ndc = n_DES_cblocks (kt); if (ndc) fixup_key_DES (key, kt, ndc); #ifdef ENABLE_DEBUG if (check_debug_level (D_CRYPTO_DEBUG)) { if (memcmp (orig.cipher, key->cipher, kt->cipher_length)) dmsg (D_CRYPTO_DEBUG, "CRYPTO INFO: fixup_key: before=%s after=%s", format_hex (orig.cipher, kt->cipher_length, 0, &gc), format_hex (key->cipher, kt->cipher_length, 0, &gc)); } #endif } gc_free (&gc); } void check_replay_iv_consistency (const struct key_type *kt, bool packet_id, bool use_iv) { if (cfb_ofb_mode (kt) && !(packet_id && use_iv)) msg (M_FATAL, "--no-replay or --no-iv cannot be used with a CFB or OFB mode cipher"); } bool cfb_ofb_mode (const struct key_type* kt) { if (kt->cipher) { const unsigned int mode = EVP_CIPHER_mode (kt->cipher); return mode == EVP_CIPH_CFB_MODE || mode == EVP_CIPH_OFB_MODE; } else return false; } /* * Generate a random key. If key_type is provided, make * sure generated key is valid for key_type. */ void generate_key_random (struct key *key, const struct key_type *kt) { int cipher_len = MAX_CIPHER_KEY_LENGTH; int hmac_len = MAX_HMAC_KEY_LENGTH; struct gc_arena gc = gc_new (); do { CLEAR (*key); if (kt) { if (kt->cipher && kt->cipher_length > 0 && kt->cipher_length <= cipher_len) cipher_len = kt->cipher_length; if (kt->digest && kt->hmac_length > 0 && kt->hmac_length <= hmac_len) hmac_len = kt->hmac_length; } if (!RAND_bytes (key->cipher, cipher_len) || !RAND_bytes (key->hmac, hmac_len)) msg (M_FATAL, "ERROR: Random number generator cannot obtain entropy for key generation"); dmsg (D_SHOW_KEY_SOURCE, "Cipher source entropy: %s", format_hex (key->cipher, cipher_len, 0, &gc)); dmsg (D_SHOW_KEY_SOURCE, "HMAC source entropy: %s", format_hex (key->hmac, hmac_len, 0, &gc)); if (kt) fixup_key (key, kt); } while (kt && !check_key (key, kt)); gc_free (&gc); } /* * Print key material */ void key2_print (const struct key2* k, const struct key_type *kt, const char* prefix0, const char* prefix1) { struct gc_arena gc = gc_new (); ASSERT (k->n == 2); dmsg (D_SHOW_KEY_SOURCE, "%s (cipher): %s", prefix0, format_hex (k->keys[0].cipher, kt->cipher_length, 0, &gc)); dmsg (D_SHOW_KEY_SOURCE, "%s (hmac): %s", prefix0, format_hex (k->keys[0].hmac, kt->hmac_length, 0, &gc)); dmsg (D_SHOW_KEY_SOURCE, "%s (cipher): %s", prefix1, format_hex (k->keys[1].cipher, kt->cipher_length, 0, &gc)); dmsg (D_SHOW_KEY_SOURCE, "%s (hmac): %s", prefix1, format_hex (k->keys[1].hmac, kt->hmac_length, 0, &gc)); gc_free (&gc); } void test_crypto (const struct crypto_options *co, struct frame* frame) { int i, j; struct gc_arena gc = gc_new (); struct buffer src = alloc_buf_gc (TUN_MTU_SIZE (frame), &gc); struct buffer work = alloc_buf_gc (BUF_SIZE (frame), &gc); struct buffer encrypt_workspace = alloc_buf_gc (BUF_SIZE (frame), &gc); struct buffer decrypt_workspace = alloc_buf_gc (BUF_SIZE (frame), &gc); struct buffer buf = clear_buf(); /* init work */ ASSERT (buf_init (&work, FRAME_HEADROOM (frame))); msg (M_INFO, "Entering " PACKAGE_NAME " crypto self-test mode."); for (i = 1; i <= TUN_MTU_SIZE (frame); ++i) { update_time (); msg (M_INFO, "TESTING ENCRYPT/DECRYPT of packet length=%d", i); /* * Load src with random data. */ ASSERT (buf_init (&src, 0)); ASSERT (i <= src.capacity); src.len = i; ASSERT (RAND_pseudo_bytes (BPTR (&src), BLEN (&src))); /* copy source to input buf */ buf = work; memcpy (buf_write_alloc (&buf, BLEN (&src)), BPTR (&src), BLEN (&src)); /* encrypt */ openvpn_encrypt (&buf, encrypt_workspace, co, frame); /* decrypt */ openvpn_decrypt (&buf, decrypt_workspace, co, frame); /* compare */ if (buf.len != src.len) msg (M_FATAL, "SELF TEST FAILED, src.len=%d buf.len=%d", src.len, buf.len); for (j = 0; j < i; ++j) { const uint8_t in = *(BPTR (&src) + j); const uint8_t out = *(BPTR (&buf) + j); if (in != out) msg (M_FATAL, "SELF TEST FAILED, pos=%d in=%d out=%d", j, in, out); } } msg (M_INFO, PACKAGE_NAME " crypto self-test mode SUCCEEDED."); gc_free (&gc); } #ifdef USE_SSL void get_tls_handshake_key (const struct key_type *key_type, struct key_ctx_bi *ctx, const char *passphrase_file, const int key_direction, const unsigned int flags) { if (passphrase_file && key_type->hmac_length) { struct key2 key2; struct key_type kt = *key_type; struct key_direction_state kds; /* for control channel we are only authenticating, not encrypting */ kt.cipher_length = 0; kt.cipher = NULL; #if ENABLE_INLINE_FILES if (flags & GHK_INLINE) { /* key was specified inline, key text is in passphrase_file */ read_key_file (&key2, passphrase_file, RKF_INLINE|RKF_MUST_SUCCEED); /* succeeded? */ if (key2.n == 2) msg (M_INFO, "Control Channel Authentication: tls-auth using INLINE static key file"); else msg (M_FATAL, "INLINE tls-auth file lacks the requisite 2 keys"); } else #endif { /* first try to parse as an OpenVPN static key file */ read_key_file (&key2, passphrase_file, 0); /* succeeded? */ if (key2.n == 2) { msg (M_INFO, "Control Channel Authentication: using '%s' as a " PACKAGE_NAME " static key file", passphrase_file); } else { int hash_size; CLEAR (key2); /* failed, now try to get hash from a freeform file */ hash_size = read_passphrase_hash (passphrase_file, kt.digest, key2.keys[0].hmac, MAX_HMAC_KEY_LENGTH); ASSERT (hash_size == kt.hmac_length); /* suceeded */ key2.n = 1; msg (M_INFO, "Control Channel Authentication: using '%s' as a free-form passphrase file", passphrase_file); } } /* handle key direction */ key_direction_state_init (&kds, key_direction); must_have_n_keys (passphrase_file, "tls-auth", &key2, kds.need_keys); /* initialize hmac key in both directions */ init_key_ctx (&ctx->encrypt, &key2.keys[kds.out_key], &kt, DO_ENCRYPT, "Outgoing Control Channel Authentication"); init_key_ctx (&ctx->decrypt, &key2.keys[kds.in_key], &kt, DO_DECRYPT, "Incoming Control Channel Authentication"); CLEAR (key2); } else { CLEAR (*ctx); } } #endif /* header and footer for static key file */ static const char static_key_head[] = "-----BEGIN " PACKAGE_NAME " Static key V1-----"; static const char static_key_foot[] = "-----END " PACKAGE_NAME " Static key V1-----"; static const char printable_char_fmt[] = "Non-Hex character ('%c') found at line %d in key file '%s' (%d/%d/%d bytes found/min/max)"; static const char unprintable_char_fmt[] = "Non-Hex, unprintable character (0x%02x) found at line %d in key file '%s' (%d/%d/%d bytes found/min/max)"; /* read key from file */ void read_key_file (struct key2 *key2, const char *file, const unsigned int flags) { struct gc_arena gc = gc_new (); struct buffer in; int fd, size; uint8_t hex_byte[3] = {0, 0, 0}; const char *error_filename = file; /* parse info */ const unsigned char *cp; int hb_index = 0; int line_num = 1; int line_index = 0; int match = 0; /* output */ uint8_t* out = (uint8_t*) &key2->keys; const int keylen = sizeof (key2->keys); int count = 0; /* parse states */ # define PARSE_INITIAL 0 # define PARSE_HEAD 1 # define PARSE_DATA 2 # define PARSE_DATA_COMPLETE 3 # define PARSE_FOOT 4 # define PARSE_FINISHED 5 int state = PARSE_INITIAL; /* constants */ const int hlen = strlen (static_key_head); const int flen = strlen (static_key_foot); const int onekeylen = sizeof (key2->keys[0]); CLEAR (*key2); /* * Key can be provided as a filename in 'file' or if RKF_INLINE * is set, the actual key data itself in ascii form. */ #if ENABLE_INLINE_FILES if (flags & RKF_INLINE) /* 'file' is a string containing ascii representation of key */ { size = strlen (file) + 1; buf_set_read (&in, (const uint8_t *)file, size); error_filename = INLINE_FILE_TAG; } else /* 'file' is a filename which refers to a file containing the ascii key */ #endif { in = alloc_buf_gc (2048, &gc); fd = open (file, O_RDONLY); if (fd == -1) msg (M_ERR, "Cannot open file key file '%s'", file); size = read (fd, in.data, in.capacity); if (size < 0) msg (M_FATAL, "Read error on key file ('%s')", file); if (size == in.capacity) msg (M_FATAL, "Key file ('%s') can be a maximum of %d bytes", file, (int)in.capacity); close (fd); } cp = (unsigned char *)in.data; while (size > 0) { const unsigned char c = *cp; #if 0 msg (M_INFO, "char='%c' s=%d ln=%d li=%d m=%d c=%d", c, state, line_num, line_index, match, count); #endif if (c == '\n') { line_index = match = 0; ++line_num; } else { /* first char of new line */ if (!line_index) { /* first char of line after header line? */ if (state == PARSE_HEAD) state = PARSE_DATA; /* first char of footer */ if ((state == PARSE_DATA || state == PARSE_DATA_COMPLETE) && c == '-') state = PARSE_FOOT; } /* compare read chars with header line */ if (state == PARSE_INITIAL) { if (line_index < hlen && c == static_key_head[line_index]) { if (++match == hlen) state = PARSE_HEAD; } } /* compare read chars with footer line */ if (state == PARSE_FOOT) { if (line_index < flen && c == static_key_foot[line_index]) { if (++match == flen) state = PARSE_FINISHED; } } /* reading key */ if (state == PARSE_DATA) { if (isxdigit(c)) { ASSERT (hb_index >= 0 && hb_index < 2); hex_byte[hb_index++] = c; if (hb_index == 2) { unsigned int u; ASSERT(sscanf((const char *)hex_byte, "%x", &u) == 1); *out++ = u; hb_index = 0; if (++count == keylen) state = PARSE_DATA_COMPLETE; } } else if (isspace(c)) ; else { msg (M_FATAL, (isprint (c) ? printable_char_fmt : unprintable_char_fmt), c, line_num, error_filename, count, onekeylen, keylen); } } ++line_index; } ++cp; --size; } /* * Normally we will read either 1 or 2 keys from file. */ key2->n = count / onekeylen; ASSERT (key2->n >= 0 && key2->n <= (int) SIZE (key2->keys)); if (flags & RKF_MUST_SUCCEED) { if (!key2->n) msg (M_FATAL, "Insufficient key material or header text not found found in file '%s' (%d/%d/%d bytes found/min/max)", error_filename, count, onekeylen, keylen); if (state != PARSE_FINISHED) msg (M_FATAL, "Footer text not found in file '%s' (%d/%d/%d bytes found/min/max)", error_filename, count, onekeylen, keylen); } /* zero file read buffer */ buf_clear (&in); if (key2->n) warn_if_group_others_accessible (error_filename); #if 0 /* DEBUGGING */ { int i; printf ("KEY READ, n=%d\n", key2->n); for (i = 0; i < (int) SIZE (key2->keys); ++i) { /* format key as ascii */ const char *fmt = format_hex_ex ((const uint8_t*)&key2->keys[i], sizeof (key2->keys[i]), 0, 16, "\n", &gc); printf ("[%d]\n%s\n\n", i, fmt); } } #endif /* pop our garbage collection level */ gc_free (&gc); } int read_passphrase_hash (const char *passphrase_file, const EVP_MD *digest, uint8_t *output, int len) { unsigned int outlen = 0; EVP_MD_CTX md; ASSERT (len >= EVP_MD_size (digest)); memset (output, 0, len); EVP_DigestInit (&md, digest); /* read passphrase file */ { const int min_passphrase_size = 8; uint8_t buf[64]; int total_size = 0; int fd = open (passphrase_file, O_RDONLY); if (fd == -1) msg (M_ERR, "Cannot open passphrase file: '%s'", passphrase_file); for (;;) { int size = read (fd, buf, sizeof (buf)); if (size == 0) break; if (size == -1) msg (M_ERR, "Read error on passphrase file: '%s'", passphrase_file); EVP_DigestUpdate (&md, buf, size); total_size += size; } close (fd); warn_if_group_others_accessible (passphrase_file); if (total_size < min_passphrase_size) msg (M_FATAL, "Passphrase file '%s' is too small (must have at least %d characters)", passphrase_file, min_passphrase_size); } EVP_DigestFinal (&md, output, &outlen); EVP_MD_CTX_cleanup (&md); return outlen; } /* * Write key to file, return number of random bits * written. */ int write_key_file (const int nkeys, const char *filename) { struct gc_arena gc = gc_new (); int fd, i; int nbits = 0; /* must be large enough to hold full key file */ struct buffer out = alloc_buf_gc (2048, &gc); struct buffer nbits_head_text = alloc_buf_gc (128, &gc); /* how to format the ascii file representation of key */ const int bytes_per_line = 16; /* open key file */ fd = open (filename, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR); if (fd == -1) msg (M_ERR, "Cannot open shared secret file '%s' for write", filename); buf_printf (&out, "%s\n", static_key_head); for (i = 0; i < nkeys; ++i) { struct key key; char* fmt; /* generate random bits */ generate_key_random (&key, NULL); /* format key as ascii */ fmt = format_hex_ex ((const uint8_t*)&key, sizeof (key), 0, bytes_per_line, "\n", &gc); /* increment random bits counter */ nbits += sizeof (key) * 8; /* write to holding buffer */ buf_printf (&out, "%s\n", fmt); /* zero memory which held key component (will be freed by GC) */ memset (fmt, 0, strlen(fmt)); CLEAR (key); } buf_printf (&out, "%s\n", static_key_foot); /* write number of bits */ buf_printf (&nbits_head_text, "#\n# %d bit " PACKAGE_NAME " static key\n#\n", nbits); buf_write_string_file (&nbits_head_text, filename, fd); /* write key file, now formatted in out, to file */ buf_write_string_file (&out, filename, fd); if (close (fd)) msg (M_ERR, "Close error on shared secret file %s", filename); /* zero memory which held file content (memory will be freed by GC) */ buf_clear (&out); /* pop our garbage collection level */ gc_free (&gc); return nbits; } void must_have_n_keys (const char *filename, const char *option, const struct key2 *key2, int n) { if (key2->n < n) { #ifdef ENABLE_SMALL msg (M_FATAL, "Key file '%s' used in --%s contains insufficient key material [keys found=%d required=%d]", filename, option, key2->n, n); #else msg (M_FATAL, "Key file '%s' used in --%s contains insufficient key material [keys found=%d required=%d] -- try generating a new key file with '" PACKAGE " --genkey --secret [file]', or use the existing key file in bidirectional mode by specifying --%s without a key direction parameter", filename, option, key2->n, n, option); #endif } } int ascii2keydirection (int msglevel, const char *str) { if (!str) return KEY_DIRECTION_BIDIRECTIONAL; else if (!strcmp (str, "0")) return KEY_DIRECTION_NORMAL; else if (!strcmp (str, "1")) return KEY_DIRECTION_INVERSE; else { msg (msglevel, "Unknown key direction '%s' -- must be '0' or '1'", str); return -1; } return KEY_DIRECTION_BIDIRECTIONAL; /* NOTREACHED */ } const char * keydirection2ascii (int kd, bool remote) { if (kd == KEY_DIRECTION_BIDIRECTIONAL) return NULL; else if (kd == KEY_DIRECTION_NORMAL) return remote ? "1" : "0"; else if (kd == KEY_DIRECTION_INVERSE) return remote ? "0" : "1"; else { ASSERT (0); } return NULL; /* NOTREACHED */ } void key_direction_state_init (struct key_direction_state *kds, int key_direction) { CLEAR (*kds); switch (key_direction) { case KEY_DIRECTION_NORMAL: kds->out_key = 0; kds->in_key = 1; kds->need_keys = 2; break; case KEY_DIRECTION_INVERSE: kds->out_key = 1; kds->in_key = 0; kds->need_keys = 2; break; case KEY_DIRECTION_BIDIRECTIONAL: kds->out_key = 0; kds->in_key = 0; kds->need_keys = 1; break; default: ASSERT (0); } } void verify_fix_key2 (struct key2 *key2, const struct key_type *kt, const char *shared_secret_file) { int i; for (i = 0; i < key2->n; ++i) { /* Fix parity for DES keys and make sure not a weak key */ fixup_key (&key2->keys[i], kt); /* This should be a very improbable failure */ if (!check_key (&key2->keys[i], kt)) msg (M_FATAL, "Key #%d in '%s' is bad. Try making a new key with --genkey.", i+1, shared_secret_file); } } /* given a key and key_type, write key to buffer */ bool write_key (const struct key *key, const struct key_type *kt, struct buffer *buf) { ASSERT (kt->cipher_length <= MAX_CIPHER_KEY_LENGTH && kt->hmac_length <= MAX_HMAC_KEY_LENGTH); if (!buf_write (buf, &kt->cipher_length, 1)) return false; if (!buf_write (buf, &kt->hmac_length, 1)) return false; if (!buf_write (buf, key->cipher, kt->cipher_length)) return false; if (!buf_write (buf, key->hmac, kt->hmac_length)) return false; return true; } /* * Given a key_type and buffer, read key from buffer. * Return: 1 on success * -1 read failure * 0 on key length mismatch */ int read_key (struct key *key, const struct key_type *kt, struct buffer *buf) { uint8_t cipher_length; uint8_t hmac_length; CLEAR (*key); if (!buf_read (buf, &cipher_length, 1)) goto read_err; if (!buf_read (buf, &hmac_length, 1)) goto read_err; if (!buf_read (buf, key->cipher, cipher_length)) goto read_err; if (!buf_read (buf, key->hmac, hmac_length)) goto read_err; if (cipher_length != kt->cipher_length || hmac_length != kt->hmac_length) goto key_len_err; return 1; read_err: msg (D_TLS_ERRORS, "TLS Error: error reading key from remote"); return -1; key_len_err: msg (D_TLS_ERRORS, "TLS Error: key length mismatch, local cipher/hmac %d/%d, remote cipher/hmac %d/%d", kt->cipher_length, kt->hmac_length, cipher_length, hmac_length); return 0; } void show_available_ciphers () { int nid; #ifndef ENABLE_SMALL printf ("The following ciphers and cipher modes are available\n" "for use with " PACKAGE_NAME ". Each cipher shown below may be\n" "used as a parameter to the --cipher option. The default\n" "key size is shown as well as whether or not it can be\n" "changed with the --keysize directive. Using a CBC mode\n" "is recommended.\n\n"); #endif for (nid = 0; nid < 10000; ++nid) /* is there a better way to get the size of the nid list? */ { const EVP_CIPHER *cipher = EVP_get_cipherbynid (nid); if (cipher && cipher_ok (OBJ_nid2sn (nid))) { const unsigned int mode = EVP_CIPHER_mode (cipher); if (mode == EVP_CIPH_CBC_MODE #ifdef ALLOW_NON_CBC_CIPHERS || mode == EVP_CIPH_CFB_MODE || mode == EVP_CIPH_OFB_MODE #endif ) printf ("%s %d bit default key (%s)\n", OBJ_nid2sn (nid), EVP_CIPHER_key_length (cipher) * 8, ((EVP_CIPHER_flags (cipher) & EVP_CIPH_VARIABLE_LENGTH) ? "variable" : "fixed")); } } printf ("\n"); } void show_available_digests () { int nid; #ifndef ENABLE_SMALL printf ("The following message digests are available for use with\n" PACKAGE_NAME ". A message digest is used in conjunction with\n" "the HMAC function, to authenticate received packets.\n" "You can specify a message digest as parameter to\n" "the --auth option.\n\n"); #endif for (nid = 0; nid < 10000; ++nid) { const EVP_MD *digest = EVP_get_digestbynid (nid); if (digest) { printf ("%s %d bit digest size\n", OBJ_nid2sn (nid), EVP_MD_size (digest) * 8); } } printf ("\n"); } void show_available_engines () { #if CRYPTO_ENGINE ENGINE *e; printf ("OpenSSL Crypto Engines\n\n"); ENGINE_load_builtin_engines (); e = ENGINE_get_first (); while (e) { printf ("%s [%s]\n", ENGINE_get_name (e), ENGINE_get_id (e)); e = ENGINE_get_next (e); } ENGINE_cleanup (); #else printf ("Sorry, OpenSSL hardware crypto engine functionality is not available.\n"); #endif } /* * Enable crypto acceleration, if available */ static bool engine_initialized = false; /* GLOBAL */ #if CRYPTO_ENGINE static ENGINE *engine_persist = NULL; /* GLOBAL */ /* Try to load an engine in a shareable library */ static ENGINE * try_load_engine (const char *engine) { ENGINE *e = ENGINE_by_id ("dynamic"); if (e) { if (!ENGINE_ctrl_cmd_string (e, "SO_PATH", engine, 0) || !ENGINE_ctrl_cmd_string (e, "LOAD", NULL, 0)) { ENGINE_free (e); e = NULL; } } return e; } static ENGINE * setup_engine (const char *engine) { ENGINE *e = NULL; ENGINE_load_builtin_engines (); if (engine) { if (strcmp (engine, "auto") == 0) { msg (M_INFO, "Initializing OpenSSL auto engine support"); ENGINE_register_all_complete (); return NULL; } if ((e = ENGINE_by_id (engine)) == NULL && (e = try_load_engine (engine)) == NULL) { msg (M_FATAL, "OpenSSL error: cannot load engine '%s'", engine); } if (!ENGINE_set_default (e, ENGINE_METHOD_ALL)) { msg (M_FATAL, "OpenSSL error: ENGINE_set_default failed on engine '%s'", engine); } msg (M_INFO, "Initializing OpenSSL support for engine '%s'", ENGINE_get_id (e)); } return e; } #endif void init_crypto_lib_engine (const char *engine_name) { if (!engine_initialized) { #if CRYPTO_ENGINE ASSERT (engine_name); ASSERT (!engine_persist); engine_persist = setup_engine (engine_name); #else msg (M_WARN, "Note: OpenSSL hardware crypto engine functionality is not available"); #endif engine_initialized = true; } } /* * This routine should have additional OpenSSL crypto library initialisations * used by both crypto and ssl components of OpenVPN. */ void init_crypto_lib () { } void uninit_crypto_lib () { #if CRYPTO_ENGINE if (engine_initialized) { ENGINE_cleanup (); engine_persist = NULL; engine_initialized = false; } #endif } /* * Random number functions, used in cases where we want * reasonably strong cryptographic random number generation * without depleting our entropy pool. Used for random * IV values and a number of other miscellaneous tasks. */ #define NONCE_SECRET_LEN 16 static uint8_t nonce_data [SHA_DIGEST_LENGTH + NONCE_SECRET_LEN]; /* GLOBAL */ void prng_init (void) { if (!RAND_bytes (nonce_data, sizeof(nonce_data))) msg (M_FATAL, "ERROR: Random number generator cannot obtain entropy for PRNG"); } void prng_bytes (uint8_t *output, int len) { SHA_CTX ctx; mutex_lock_static (L_PRNG); while (len > 0) { const int blen = min_int (len, SHA_DIGEST_LENGTH); SHA1_Init (&ctx); SHA1_Update (&ctx, nonce_data, sizeof (nonce_data)); SHA1_Final (nonce_data, &ctx); memcpy (output, nonce_data, blen); output += blen; len -= blen; } mutex_unlock_static (L_PRNG); } /* an analogue to the random() function, but use prng_bytes */ long int get_random() { long int l; prng_bytes ((unsigned char *)&l, sizeof(l)); if (l < 0) l = -l; return l; } const char * md5sum (uint8_t *buf, int len, int n_print_chars, struct gc_arena *gc) { uint8_t digest[MD5_DIGEST_LENGTH]; MD5 (buf, len, digest); return format_hex (digest, MD5_DIGEST_LENGTH, n_print_chars, gc); } /* * OpenSSL memory debugging. If dmalloc debugging is enabled, tell * OpenSSL to use our private malloc/realloc/free functions so that * we can dispatch them to dmalloc. */ #ifdef DMALLOC static void * crypto_malloc (size_t size, const char *file, int line) { return dmalloc_malloc(file, line, size, DMALLOC_FUNC_MALLOC, 0, 0); } static void * crypto_realloc (void *ptr, size_t size, const char *file, int line) { return dmalloc_realloc(file, line, ptr, size, DMALLOC_FUNC_REALLOC, 0); } static void crypto_free (void *ptr) { dmalloc_free (__FILE__, __LINE__, ptr, DMALLOC_FUNC_FREE); } void openssl_dmalloc_init (void) { CRYPTO_set_mem_ex_functions (crypto_malloc, crypto_realloc, crypto_free); } #endif /* DMALLOC */ #ifndef USE_SSL void init_ssl_lib (void) { ERR_load_crypto_strings (); OpenSSL_add_all_algorithms (); init_crypto_lib (); } void free_ssl_lib (void) { uninit_crypto_lib (); EVP_cleanup (); ERR_free_strings (); } #endif /* USE_SSL */ #endif /* USE_CRYPTO */