Blob Blame History Raw
From 474075d2cb8c8ced7764b1b4b5ad63a49284d61f Mon Sep 17 00:00:00 2001
From: TJ Saunders <tj@castaglia.org>
Date: Thu, 17 Nov 2016 07:11:07 -0800
Subject: [PATCH 1/6] Bug#4275: Support OpenSSL 1.1.x API for 1.3.5 line.

---
 NEWS                        |   1 +
 RELEASE_NOTES               |   1 +
 contrib/mod_sftp/cipher.c   | 113 ++++++---
 contrib/mod_sftp/cipher.h   |   7 +-
 contrib/mod_sftp/crypto.c   | 177 +++++++++++---
 contrib/mod_sftp/kex.c      | 390 ++++++++++++++++++++++++------
 contrib/mod_sftp/keys.c     | 389 ++++++++++++++++++++++++------
 contrib/mod_sftp/mac.c      | 161 +++++++++----
 contrib/mod_sftp/mod_sftp.c |   6 +-
 contrib/mod_sftp/msg.c      |   5 +-
 contrib/mod_sql.c           |  16 +-
 contrib/mod_sql_passwd.c    |  35 +--
 contrib/mod_tls.c           | 575 ++++++++++++++++++++++++++++----------------
 contrib/mod_tls.h           |   2 +-
 contrib/mod_tls_shmcache.c  |  32 +--
 src/table.c                 |  10 +-
 16 files changed, 1389 insertions(+), 531 deletions(-)

#diff --git a/NEWS b/NEWS
#index 5590345..40ed935 100644
#--- a/NEWS
#+++ b/NEWS
#@@ -16,6 +16,7 @@
# - Bug 4255 - "AuthAliasOnly on" in server config breaks anonymous logins.
# - Bug 4272 - CapabilitiesEngine directive not honored for <IfUser>/<IfGroup>
#   sections.
#+- Bug 4275 - Support OpenSSL 1.1.x API..
# 
# 1.3.5b - Released 10-Mar-2016
# --------------------------------
#diff --git a/RELEASE_NOTES b/RELEASE_NOTES
#index 6f8e41b..9dda5ca 100644
#--- a/RELEASE_NOTES
#+++ b/RELEASE_NOTES
#@@ -9,6 +9,7 @@ ChangeLog files.
# 1.3.5c
# ---------
# 
#+  + Support for OpenSSL 1.1.x API changes.
#   + Fixed handling of CapabilitiesEngine in <IfUser>/<IfGroup> sections.
# 
# 
diff --git a/contrib/mod_sftp/cipher.c b/contrib/mod_sftp/cipher.c
index 9ed4ed7..eefbf38 100644
--- a/contrib/mod_sftp/cipher.c
+++ b/contrib/mod_sftp/cipher.c
@@ -1,6 +1,6 @@
 /*
  * ProFTPD - mod_sftp ciphers
- * Copyright (c) 2008-2014 TJ Saunders
+ * Copyright (c) 2008-2016 TJ Saunders
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -20,8 +20,6 @@
  * give permission to link this program with OpenSSL, and distribute the
  * resulting executable, without including the source code for OpenSSL in the
  * source distribution.
- *
- * $Id: cipher.c,v 1.18 2014-03-02 06:07:43 castaglia Exp $
  */
 
 #include "mod_sftp.h"
@@ -56,13 +54,13 @@ static struct sftp_cipher read_ciphers[2] = {
   { NULL, NULL, NULL, 0, NULL, 0, 0 },
   { NULL, NULL, NULL, 0, NULL, 0, 0 }
 };
-static EVP_CIPHER_CTX read_ctxs[2]; 
+static EVP_CIPHER_CTX *read_ctxs[2]; 
 
 static struct sftp_cipher write_ciphers[2] = {
   { NULL, NULL, NULL, 0, NULL, 0, 0 },
   { NULL, NULL, NULL, 0, NULL, 0, 0 }
 };
-static EVP_CIPHER_CTX write_ctxs[2];
+static EVP_CIPHER_CTX *write_ctxs[2];
 
 #define SFTP_CIPHER_DEFAULT_BLOCK_SZ		8
 static size_t cipher_blockszs[2] = {
@@ -96,7 +94,7 @@ static void switch_read_cipher(void) {
   /* First, clear the context of the existing read cipher, if any. */
   if (read_ciphers[read_cipher_idx].key) {
     clear_cipher(&(read_ciphers[read_cipher_idx]));
-    if (EVP_CIPHER_CTX_cleanup(&(read_ctxs[read_cipher_idx])) != 1) {
+    if (EVP_CIPHER_CTX_cleanup(read_ctxs[read_cipher_idx]) != 1) {
       (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
         "error clearing cipher context: %s", sftp_crypto_get_errors());
     }
@@ -117,7 +115,7 @@ static void switch_write_cipher(void) {
   /* First, clear the context of the existing read cipher, if any. */
   if (write_ciphers[write_cipher_idx].key) {
     clear_cipher(&(write_ciphers[write_cipher_idx]));
-    if (EVP_CIPHER_CTX_cleanup(&(write_ctxs[write_cipher_idx])) != 1) {
+    if (EVP_CIPHER_CTX_cleanup(write_ctxs[write_cipher_idx]) != 1) {
       (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
         "error clearing cipher context: %s", sftp_crypto_get_errors());
     }
@@ -156,8 +154,7 @@ static void clear_cipher(struct sftp_cipher *cipher) {
 static int set_cipher_iv(struct sftp_cipher *cipher, const EVP_MD *hash,
     const unsigned char *k, uint32_t klen, const char *h, uint32_t hlen,
     char *letter, const unsigned char *id, uint32_t id_len) {
-
-  EVP_MD_CTX ctx;
+  EVP_MD_CTX *ctx;
   unsigned char *iv = NULL;
   size_t cipher_iv_len = 0, iv_sz = 0;
   uint32_t iv_len = 0;
@@ -191,14 +188,16 @@ static int set_cipher_iv(struct sftp_cipher *cipher, const EVP_MD *hash,
     _exit(1);
   }
 
-  EVP_DigestInit(&ctx, hash);
+  ctx = EVP_MD_CTX_create();
+  EVP_DigestInit(ctx, hash);
   if (sftp_interop_supports_feature(SFTP_SSH2_FEAT_CIPHER_USE_K)) {
-    EVP_DigestUpdate(&ctx, k, klen);
+    EVP_DigestUpdate(ctx, k, klen);
   }
-  EVP_DigestUpdate(&ctx, h, hlen);
-  EVP_DigestUpdate(&ctx, letter, sizeof(char));
-  EVP_DigestUpdate(&ctx, (char *) id, id_len);
-  EVP_DigestFinal(&ctx, iv, &iv_len);
+  EVP_DigestUpdate(ctx, h, hlen);
+  EVP_DigestUpdate(ctx, letter, sizeof(char));
+  EVP_DigestUpdate(ctx, (char *) id, id_len);
+  EVP_DigestFinal(ctx, iv, &iv_len);
+  EVP_MD_CTX_destroy(ctx);
 
   /* If we need more, keep hashing, as per RFC, until we have enough
    * material.
@@ -208,13 +207,15 @@ static int set_cipher_iv(struct sftp_cipher *cipher, const EVP_MD *hash,
 
     pr_signals_handle();
 
-    EVP_DigestInit(&ctx, hash);
+    ctx = EVP_MD_CTX_create();
+    EVP_DigestInit(ctx, hash);
     if (sftp_interop_supports_feature(SFTP_SSH2_FEAT_CIPHER_USE_K)) {
-      EVP_DigestUpdate(&ctx, k, klen);
+      EVP_DigestUpdate(ctx, k, klen);
     }
-    EVP_DigestUpdate(&ctx, h, hlen);
-    EVP_DigestUpdate(&ctx, iv, len);
-    EVP_DigestFinal(&ctx, iv + len, &len);
+    EVP_DigestUpdate(ctx, h, hlen);
+    EVP_DigestUpdate(ctx, iv, len);
+    EVP_DigestFinal(ctx, iv + len, &len);
+    EVP_MD_CTX_destroy(ctx);
 
     iv_len += len;
   }
@@ -228,8 +229,7 @@ static int set_cipher_iv(struct sftp_cipher *cipher, const EVP_MD *hash,
 static int set_cipher_key(struct sftp_cipher *cipher, const EVP_MD *hash,
     const unsigned char *k, uint32_t klen, const char *h, uint32_t hlen,
     char *letter, const unsigned char *id, uint32_t id_len) {
-
-  EVP_MD_CTX ctx;
+  EVP_MD_CTX *ctx;
   unsigned char *key = NULL;
   size_t key_sz = 0;
   uint32_t key_len = 0;
@@ -258,12 +258,14 @@ static int set_cipher_key(struct sftp_cipher *cipher, const EVP_MD *hash,
     _exit(1);
   }
 
-  EVP_DigestInit(&ctx, hash);
-  EVP_DigestUpdate(&ctx, k, klen);
-  EVP_DigestUpdate(&ctx, h, hlen);
-  EVP_DigestUpdate(&ctx, letter, sizeof(char));
-  EVP_DigestUpdate(&ctx, (char *) id, id_len);
-  EVP_DigestFinal(&ctx, key, &key_len);
+  ctx = EVP_MD_CTX_create();
+  EVP_DigestInit(ctx, hash);
+  EVP_DigestUpdate(ctx, k, klen);
+  EVP_DigestUpdate(ctx, h, hlen);
+  EVP_DigestUpdate(ctx, letter, sizeof(char));
+  EVP_DigestUpdate(ctx, (char *) id, id_len);
+  EVP_DigestFinal(ctx, key, &key_len);
+  EVP_MD_CTX_destroy(ctx);
 
   /* If we need more, keep hashing, as per RFC, until we have enough
    * material.
@@ -273,11 +275,13 @@ static int set_cipher_key(struct sftp_cipher *cipher, const EVP_MD *hash,
 
     pr_signals_handle();
 
-    EVP_DigestInit(&ctx, hash);
-    EVP_DigestUpdate(&ctx, k, klen);
-    EVP_DigestUpdate(&ctx, h, hlen);
-    EVP_DigestUpdate(&ctx, key, len);
-    EVP_DigestFinal(&ctx, key + len, &len);
+    ctx = EVP_MD_CTX_create();
+    EVP_DigestInit(ctx, hash);
+    EVP_DigestUpdate(ctx, k, klen);
+    EVP_DigestUpdate(ctx, h, hlen);
+    EVP_DigestUpdate(ctx, key, len);
+    EVP_DigestFinal(ctx, key + len, &len);
+    EVP_MD_CTX_destroy(ctx);
 
     key_len += len;
   }
@@ -381,7 +385,7 @@ int sftp_cipher_set_read_key(pool *p, const EVP_MD *hash, const BIGNUM *k,
   switch_read_cipher();
 
   cipher = &(read_ciphers[read_cipher_idx]);
-  cipher_ctx = &(read_ctxs[read_cipher_idx]);
+  cipher_ctx = read_ctxs[read_cipher_idx];
 
   /* XXX EVP_CIPHER_CTX_init() first appeared in OpenSSL 0.9.7.  What to do
    * for older OpenSSL installations?
@@ -460,7 +464,7 @@ int sftp_cipher_read_data(pool *p, unsigned char *data, uint32_t data_len,
   size_t cipher_blocksz;
 
   cipher = &(read_ciphers[read_cipher_idx]);
-  cipher_ctx = &(read_ctxs[read_cipher_idx]);
+  cipher_ctx = read_ctxs[read_cipher_idx];
   cipher_blocksz = cipher_blockszs[read_cipher_idx];
 
   if (cipher->key) {
@@ -544,7 +548,7 @@ int sftp_cipher_set_write_key(pool *p, const EVP_MD *hash, const BIGNUM *k,
   switch_write_cipher();
 
   cipher = &(write_ciphers[write_cipher_idx]);
-  cipher_ctx = &(write_ctxs[write_cipher_idx]);
+  cipher_ctx = write_ctxs[write_cipher_idx];
 
   /* XXX EVP_CIPHER_CTX_init() first appeared in OpenSSL 0.9.7.  What to do
    * for older OpenSSL installations?
@@ -621,7 +625,7 @@ int sftp_cipher_write_data(struct ssh2_packet *pkt, unsigned char *buf,
   EVP_CIPHER_CTX *cipher_ctx;
 
   cipher = &(write_ciphers[write_cipher_idx]);
-  cipher_ctx = &(write_ctxs[write_cipher_idx]);
+  cipher_ctx = write_ctxs[write_cipher_idx];
 
   if (cipher->key) {
     int res;
@@ -671,3 +675,38 @@ int sftp_cipher_write_data(struct ssh2_packet *pkt, unsigned char *buf,
   *buflen = 0;
   return 0;
 }
+
+#if OPENSSL_VERSION_NUMBER < 0x1000000fL
+/* In older versions of OpenSSL, there was not a way to dynamically allocate
+ * an EVP_CIPHER_CTX object.  Thus we have these static objects for those
+ * older versions.
+ */
+static EVP_CIPHER_CTX read_ctx1, read_ctx2;
+static EVP_CIPHER_CTX write_ctx1, write_ctx2;
+#endif /* prior to OpenSSL-1.0.0 */
+
+int sftp_cipher_init(void) {
+#if OPENSSL_VERSION_NUMBER < 0x1000000fL
+  read_ctxs[0] = &read_ctx1;
+  read_ctxs[1] = &read_ctx2;
+  write_ctxs[0] = &write_ctx1;
+  write_ctxs[1] = &write_ctx2;
+#else
+  read_ctxs[0] = EVP_CIPHER_CTX_new();
+  read_ctxs[1] = EVP_CIPHER_CTX_new();
+  write_ctxs[0] = EVP_CIPHER_CTX_new();
+  write_ctxs[1] = EVP_CIPHER_CTX_new();
+#endif /* OpenSSL-1.0.0 and later */
+  return 0;
+}
+
+int sftp_cipher_free(void) {
+#if OPENSSL_VERSION_NUMBER >= 0x1000000fL
+  EVP_CIPHER_CTX_free(read_ctxs[0]);
+  EVP_CIPHER_CTX_free(read_ctxs[1]);
+  EVP_CIPHER_CTX_free(write_ctxs[0]);
+  EVP_CIPHER_CTX_free(write_ctxs[1]);
+#endif /* OpenSSL-1.0.0 and later */
+  return 0;
+}
+
diff --git a/contrib/mod_sftp/cipher.h b/contrib/mod_sftp/cipher.h
index 4067386..b6421e0 100644
--- a/contrib/mod_sftp/cipher.h
+++ b/contrib/mod_sftp/cipher.h
@@ -1,6 +1,6 @@
 /*
  * ProFTPD - mod_sftp cipher mgmt
- * Copyright (c) 2008-2013 TJ Saunders
+ * Copyright (c) 2008-2016 TJ Saunders
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -20,8 +20,6 @@
  * give permission to link this program with OpenSSL, and distribute the
  * resulting executable, without including the source code for OpenSSL in the
  * source distribution.
- *
- * $Id: cipher.h,v 1.4 2013-01-29 07:29:22 castaglia Exp $
  */
 
 #include "mod_sftp.h"
@@ -29,6 +27,9 @@
 #ifndef MOD_SFTP_CIPHER_H
 #define MOD_SFTP_CIPHER_H
 
+int sftp_cipher_init(void);
+int sftp_cipher_free(void);
+
 /* Returns the cipher block size, or 8, whichever is larger. This value is
  * used when reading in the first bytes of a packet in order to determine
  * the packet length.  See RFC4253, Section 6, "Binary Packet Protocol".
diff --git a/contrib/mod_sftp/crypto.c b/contrib/mod_sftp/crypto.c
index 0c8ea31..1f5e5e3 100644
--- a/contrib/mod_sftp/crypto.c
+++ b/contrib/mod_sftp/crypto.c
@@ -1,6 +1,6 @@
 /*
  * ProFTPD - mod_sftp OpenSSL interface
- * Copyright (c) 2008-2014 TJ Saunders
+ * Copyright (c) 2008-2016 TJ Saunders
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -20,8 +20,6 @@
  * give permission to link this program with OpenSSL, and distribute the
  * resulting executable, without including the source code for OpenSSL in the
  * source distribution.
- *
- * $Id: crypto.c,v 1.33 2014-01-28 17:26:17 castaglia Exp $
  */
 
 #include "mod_sftp.h"
@@ -298,6 +296,20 @@ static int do_bf_ctr(EVP_CIPHER_CTX *ctx, unsigned char *dst,
 }
 
 static const EVP_CIPHER *get_bf_ctr_cipher(void) {
+  EVP_CIPHER *cipher;
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+  /* XXX TODO: At some point, we also need to call EVP_CIPHER_meth_free() on
+   * this, to avoid a resource leak.
+   */
+  cipher = EVP_CIPHER_meth_new(NID_bf_cbc, BF_BLOCK, 32);
+  EVP_CIPHER_meth_set_iv_length(cipher, BF_BLOCK);
+  EVP_CIPHER_meth_set_init(cipher, init_bf_ctr);
+  EVP_CIPHER_meth_set_cleanup(cipher, cleanup_bf_ctr);
+  EVP_CIPHER_meth_set_do_cipher(cipher, do_bf_ctr);
+  EVP_CIPHER_meth_set_flags(cipher, EVP_CIPH_CBC_MODE|EVP_CIPH_VARIABLE_LENGTH|EVP_CIPH_ALWAYS_CALL_INIT|EVP_CIPH_CUSTOM_IV);
+
+#else
   static EVP_CIPHER bf_ctr_cipher;
 
   memset(&bf_ctr_cipher, 0, sizeof(EVP_CIPHER));
@@ -312,7 +324,10 @@ static const EVP_CIPHER *get_bf_ctr_cipher(void) {
 
   bf_ctr_cipher.flags = EVP_CIPH_CBC_MODE|EVP_CIPH_VARIABLE_LENGTH|EVP_CIPH_ALWAYS_CALL_INIT|EVP_CIPH_CUSTOM_IV;
 
-  return &bf_ctr_cipher;
+  cipher = &bf_ctr_cipher;
+#endif /* prior to OpenSSL-1.1.0 */
+
+  return cipher;
 }
 
 #if OPENSSL_VERSION_NUMBER > 0x000907000L
@@ -447,6 +462,28 @@ static int do_des3_ctr(EVP_CIPHER_CTX *ctx, unsigned char *dst,
 }
 
 static const EVP_CIPHER *get_des3_ctr_cipher(void) {
+  EVP_CIPHER *cipher;
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+  unsigned long flags;
+
+  /* XXX TODO: At some point, we also need to call EVP_CIPHER_meth_free() on
+   * this, to avoid a resource leak.
+   */
+  cipher = EVP_CIPHER_meth_new(NID_des_ede3_ecb, 8, 24);
+  EVP_CIPHER_meth_set_iv_length(cipher, 8);
+  EVP_CIPHER_meth_set_init(cipher, init_des3_ctr);
+  EVP_CIPHER_meth_set_cleanup(cipher, cleanup_des3_ctr);
+  EVP_CIPHER_meth_set_do_cipher(cipher, do_des3_ctr);
+
+  flags = EVP_CIPH_CBC_MODE|EVP_CIPH_VARIABLE_LENGTH|EVP_CIPH_ALWAYS_CALL_INIT|EVP_CIPH_CUSTOM_IV;
+#ifdef OPENSSL_FIPS
+  flags |= EVP_CIPH_FLAG_FIPS;
+#endif /* OPENSSL_FIPS */
+
+  EVP_CIPHER_meth_set_flags(cipher, flags);
+
+#else
   static EVP_CIPHER des3_ctr_cipher;
 
   memset(&des3_ctr_cipher, 0, sizeof(EVP_CIPHER));
@@ -464,7 +501,10 @@ static const EVP_CIPHER *get_des3_ctr_cipher(void) {
   des3_ctr_cipher.flags |= EVP_CIPH_FLAG_FIPS;
 #endif /* OPENSSL_FIPS */
 
-  return &des3_ctr_cipher;
+  cipher = &des3_ctr_cipher;
+#endif /* prior to OpenSSL-1.1.0 */
+
+  return cipher;
 }
 
 /* AES CTR mode implementation */
@@ -530,7 +570,8 @@ static int cleanup_aes_ctr(EVP_CIPHER_CTX *ctx) {
 static int do_aes_ctr(EVP_CIPHER_CTX *ctx, unsigned char *dst,
     const unsigned char *src, size_t len) {
   struct aes_ctr_ex *ace;
-# if OPENSSL_VERSION_NUMBER <= 0x0090704fL
+# if OPENSSL_VERSION_NUMBER <= 0x0090704fL || \
+     OPENSSL_VERSION_NUMBER >= 0x10100000L
   unsigned int n;
   unsigned char buf[AES_BLOCK_SIZE];
 # endif
@@ -542,7 +583,8 @@ static int do_aes_ctr(EVP_CIPHER_CTX *ctx, unsigned char *dst,
   if (ace == NULL)
     return 0;
 
-# if OPENSSL_VERSION_NUMBER <= 0x0090704fL
+# if OPENSSL_VERSION_NUMBER <= 0x0090704fL || \
+     OPENSSL_VERSION_NUMBER >= 0x10100000L
   /* In OpenSSL-0.9.7d and earlier, the AES CTR code did not properly handle
    * the IV as big-endian; this would cause the dreaded "Incorrect MAC
    * received on packet" error when using clients e.g. PuTTy.  To see
@@ -580,29 +622,29 @@ static int do_aes_ctr(EVP_CIPHER_CTX *ctx, unsigned char *dst,
   return 1;
 }
 
-static const EVP_CIPHER *get_aes_ctr_cipher(int key_len) {
-  static EVP_CIPHER aes_ctr_cipher;
-
-  memset(&aes_ctr_cipher, 0, sizeof(EVP_CIPHER));
+static int get_aes_ctr_cipher_nid(int key_len) {
+  int nid;
 
 #ifdef OPENSSL_FIPS
   /* Set the NID depending on the key len. */
   switch (key_len) {
     case 16:
-      aes_ctr_cipher.nid = NID_aes_128_cbc;
+      nid = NID_aes_128_cbc;
       break;
 
     case 24:
-      aes_ctr_cipher.nid = NID_aes_192_cbc;
+      nid = NID_aes_192_cbc;
       break;
 
     case 32:
-      aes_ctr_cipher.nid = NID_aes_256_cbc;
+      nid = NID_aes_256_cbc;
       break;
 
     default:
-      aes_ctr_cipher.nid = NID_undef;
+      nid = NID_undef;
+      break;
   }
+
 #else
   /* Setting this nid member to something other than NID_undef causes
    * interesting problems on an OpenSolaris system, using the provided
@@ -630,9 +672,41 @@ static const EVP_CIPHER *get_aes_ctr_cipher(int key_len) {
    *  debug1: Calling cleanup 0x807cc14(0x0)
    *  Couldn't read packet: Error 0
    */
-  aes_ctr_cipher.nid = NID_undef;
+  nid = NID_undef;
 #endif /* OPENSSL_FIPS */
 
+  return nid;
+}
+
+static const EVP_CIPHER *get_aes_ctr_cipher(int key_len) {
+  EVP_CIPHER *cipher;
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+  unsigned long flags;
+
+  /* XXX TODO: At some point, we also need to call EVP_CIPHER_meth_free() on
+   * this, to avoid a resource leak.
+   */
+  cipher = EVP_CIPHER_meth_new(get_aes_ctr_cipher_nid(key_len), AES_BLOCK_SIZE,
+    key_len);
+  EVP_CIPHER_meth_set_iv_length(cipher, AES_BLOCK_SIZE);
+  EVP_CIPHER_meth_set_init(cipher, init_aes_ctr);
+  EVP_CIPHER_meth_set_cleanup(cipher, cleanup_aes_ctr);
+  EVP_CIPHER_meth_set_do_cipher(cipher, do_aes_ctr);
+
+  flags = EVP_CIPH_CBC_MODE|EVP_CIPH_VARIABLE_LENGTH|EVP_CIPH_ALWAYS_CALL_INIT|EVP_CIPH_CUSTOM_IV;
+#ifdef OPENSSL_FIPS
+  flags |= EVP_CIPH_FLAG_FIPS;
+#endif /* OPENSSL_FIPS */
+
+  EVP_CIPHER_meth_set_flags(cipher, flags);
+
+#else
+  static EVP_CIPHER aes_ctr_cipher;
+
+  memset(&aes_ctr_cipher, 0, sizeof(EVP_CIPHER));
+
+  aes_ctr_cipher.nid = get_aes_ctr_cipher_nid(key_len);
   aes_ctr_cipher.block_size = AES_BLOCK_SIZE;
   aes_ctr_cipher.iv_len = AES_BLOCK_SIZE;
   aes_ctr_cipher.key_len = key_len;
@@ -641,51 +715,93 @@ static const EVP_CIPHER *get_aes_ctr_cipher(int key_len) {
   aes_ctr_cipher.do_cipher = do_aes_ctr;
 
   aes_ctr_cipher.flags = EVP_CIPH_CBC_MODE|EVP_CIPH_VARIABLE_LENGTH|EVP_CIPH_ALWAYS_CALL_INIT|EVP_CIPH_CUSTOM_IV;
-#ifdef OPENSSL_FIPS
+# ifdef OPENSSL_FIPS
   aes_ctr_cipher.flags |= EVP_CIPH_FLAG_FIPS;
-#endif /* OPENSSL_FIPS */
+# endif /* OPENSSL_FIPS */
 
-  return &aes_ctr_cipher;
+  cipher = &aes_ctr_cipher;
+#endif /* prior to OpenSSL-1.1.0 */
+
+  return cipher;
 }
 
 static int update_umac(EVP_MD_CTX *ctx, const void *data, size_t len) {
   int res;
+  void *md_data;
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+  md_data = EVP_MD_CTX_md_data(ctx);
+#else
+  md_data = ctx->md_data;
+#endif /* prior to OpenSSL-1.1.0 */
 
-  if (ctx->md_data == NULL) {
+  if (md_data == NULL) {
     struct umac_ctx *umac;
+    void **ptr;
 
     umac = umac_new((unsigned char *) data);
     if (umac == NULL) {
       return 0;
     }
 
-    ctx->md_data = umac;
+    ptr = &md_data;
+    *ptr = umac;
     return 1;
   }
 
-  res = umac_update(ctx->md_data, (unsigned char *) data, (long) len);
+  res = umac_update(md_data, (unsigned char *) data, (long) len);
   return res;
 }
 
 static int final_umac(EVP_MD_CTX *ctx, unsigned char *md) {
   unsigned char nonce[8];
   int res;
+  void *md_data;
 
-  res = umac_final(ctx->md_data, md, nonce);
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+  md_data = EVP_MD_CTX_md_data(ctx);
+#else
+  md_data = ctx->md_data;
+#endif /* prior to OpenSSL-1.1.0 */
+
+  res = umac_final(md_data, md, nonce);
   return res;
 }
 
 static int delete_umac(EVP_MD_CTX *ctx) {
   struct umac_ctx *umac;
+  void *md_data, **ptr;
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+  md_data = EVP_MD_CTX_md_data(ctx);
+#else
+  md_data = ctx->md_data;
+#endif /* prior to OpenSSL-1.1.0 */
 
-  umac = ctx->md_data;
+  umac = md_data;
   umac_delete(umac);
-  ctx->md_data = NULL;
+
+  ptr = &md_data;
+  *ptr = NULL;
 
   return 1;
 }
 
 static const EVP_MD *get_umac_digest(void) {
+  EVP_MD *md;
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+  /* XXX TODO: At some point, we also need to call EVP_MD_meth_free() on
+   * this, to avoid a resource leak.
+   */
+  md = EVP_MD_meth_new(NID_undef, NID_undef);
+  EVP_MD_meth_set_input_blocksize(md, 32);
+  EVP_MD_meth_set_result_size(md, 8);
+  EVP_MD_meth_set_flags(md, 0UL);
+  EVP_MD_meth_set_update(md, update_umac);
+  EVP_MD_meth_set_final(md, final_umac);
+  EVP_MD_meth_set_cleanup(md, delete_umac);
+#else
   static EVP_MD umac_digest;
 
   memset(&umac_digest, 0, sizeof(EVP_MD));
@@ -694,12 +810,15 @@ static const EVP_MD *get_umac_digest(void) {
   umac_digest.pkey_type = NID_undef;
   umac_digest.md_size = 8;
   umac_digest.flags = 0UL;
-  umac_digest.update = update_umac;
-  umac_digest.final = final_umac;
-  umac_digest.cleanup = delete_umac;
+  umac_digest.update = update_umac64;
+  umac_digest.final = final_umac64;
+  umac_digest.cleanup = delete_umac64;
   umac_digest.block_size = 32;
 
-  return &umac_digest;
+  md = &umac_digest;
+#endif /* prior to OpenSSL-1.1.0 */
+
+  return md;
 }
 #endif /* OpenSSL older than 0.9.7 */
 
diff --git a/contrib/mod_sftp/kex.c b/contrib/mod_sftp/kex.c
index a871512..79d4ac8 100644
--- a/contrib/mod_sftp/kex.c
+++ b/contrib/mod_sftp/kex.c
@@ -186,7 +186,11 @@ static int kex_rekey_timer_cb(CALLBACK_FRAME) {
 static const unsigned char *calculate_h(struct sftp_kex *kex,
     const unsigned char *hostkey_data, size_t hostkey_datalen, const BIGNUM *k,
     uint32_t *hlen) {
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
   EVP_MD_CTX ctx;
+#endif /* prior to OpenSSL-1.1.0 */
+  EVP_MD_CTX *pctx;
+  const BIGNUM *dh_pub_key = NULL;
   unsigned char *buf, *ptr;
   uint32_t buflen, bufsz;
 
@@ -220,55 +224,79 @@ static const unsigned char *calculate_h(struct sftp_kex *kex,
   sftp_msg_write_mpint(&buf, &buflen, kex->e);
 
   /* Server's key */
-  sftp_msg_write_mpint(&buf, &buflen, kex->dh->pub_key);
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+  DH_get0_key(kex->dh, &dh_pub_key, NULL);
+#else
+  dh_pub_key = kex->dh->pub_key;
+#endif /* prior to OpenSSL-1.1.0 */
+  sftp_msg_write_mpint(&buf, &buflen, dh_pub_key);
 
   /* Shared secret */
   sftp_msg_write_mpint(&buf, &buflen, k);
 
+#if OPENSSL_VERSION_NUMBER >= 0x10100000LL
+  pctx = EVP_MD_CTX_new();
+#else
+  pctx = &ctx;
+#endif /* OpenSSL-1.1.0 and later */
+
   /* In OpenSSL 0.9.6, many of the EVP_Digest* functions returned void, not
    * int.  Without these ugly OpenSSL version preprocessor checks, the
    * compiler will error out with "void value not ignored as it ought to be".
    */
 
 #if OPENSSL_VERSION_NUMBER >= 0x000907000L
-  if (EVP_DigestInit(&ctx, kex->hash) != 1) {
+  if (EVP_DigestInit(pctx, kex->hash) != 1) {
     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
       "error initializing message digest: %s", sftp_crypto_get_errors());
     BN_clear_free(kex->e);
     kex->e = NULL;
     pr_memscrub(ptr, bufsz);
+# if OPENSSL_VERSION_NUMBER >= 0x10100000LL
+    EVP_MD_CTX_free(pctx);
+# endif /* OpenSSL-1.1.0 and later */
     return NULL;
   }
 #else
-  EVP_DigestInit(&ctx, kex->hash);
+  EVP_DigestInit(pctx, kex->hash);
 #endif
 
 #if OPENSSL_VERSION_NUMBER >= 0x000907000L
-  if (EVP_DigestUpdate(&ctx, ptr, (bufsz - buflen)) != 1) {
+  if (EVP_DigestUpdate(pctx, ptr, (bufsz - buflen)) != 1) {
     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
       "error updating message digest: %s", sftp_crypto_get_errors());
     BN_clear_free(kex->e);
     kex->e = NULL;
     pr_memscrub(ptr, bufsz);
+# if OPENSSL_VERSION_NUMBER >= 0x10100000LL
+    EVP_MD_CTX_free(pctx);
+# endif /* OpenSSL-1.1.0 and later */
     return NULL;
   }
 #else
-  EVP_DigestUpdate(&ctx, ptr, (bufsz - buflen));
+  EVP_DigestUpdate(pctx, ptr, (bufsz - buflen));
 #endif
 
 #if OPENSSL_VERSION_NUMBER >= 0x000907000L
-  if (EVP_DigestFinal(&ctx, kex_digest_buf, hlen) != 1) {
+  if (EVP_DigestFinal(pctx, kex_digest_buf, hlen) != 1) {
     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
       "error finalizing message digest: %s", sftp_crypto_get_errors());
     BN_clear_free(kex->e);
     kex->e = NULL;
     pr_memscrub(ptr, bufsz);
+# if OPENSSL_VERSION_NUMBER >= 0x10100000LL
+    EVP_MD_CTX_free(pctx);
+# endif /* OpenSSL-1.1.0 and later */
     return NULL;
   }
 #else
-  EVP_DigestFinal(&ctx, kex_digest_buf, hlen);
+  EVP_DigestFinal(pctx, kex_digest_buf, hlen);
 #endif
 
+#if OPENSSL_VERSION_NUMBER >= 0x10100000LL
+  EVP_MD_CTX_free(pctx);
+#endif /* OpenSSL-1.1.0 and later */
+
   BN_clear_free(kex->e);
   kex->e = NULL;
 
@@ -279,7 +307,11 @@ static const unsigned char *calculate_h(struct sftp_kex *kex,
 static const unsigned char *calculate_gex_h(struct sftp_kex *kex,
     const unsigned char *hostkey_data, size_t hostkey_datalen, const BIGNUM *k,
     uint32_t min, uint32_t pref, uint32_t max, uint32_t *hlen) {
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
   EVP_MD_CTX ctx;
+#endif /* prior to OpenSSL-1.1.0 */
+  EVP_MD_CTX *pctx;
+  const BIGNUM *dh_p = NULL, *dh_g = NULL, *dh_pub_key = NULL;
   unsigned char *buf, *ptr;
   uint32_t buflen, bufsz;
 
@@ -321,62 +353,92 @@ static const unsigned char *calculate_gex_h(struct sftp_kex *kex,
     sftp_msg_write_int(&buf, &buflen, max);
   }
 
-  sftp_msg_write_mpint(&buf, &buflen, kex->dh->p);
-  sftp_msg_write_mpint(&buf, &buflen, kex->dh->g);
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+  DH_get0_pqg(kex->dh, &dh_p, NULL, &dh_g);
+#else
+  dh_p = kex->dh->p;
+  dh_g = kex->dh->g;
+#endif /* prior to OpenSSL-1.1.0 */
+  sftp_msg_write_mpint(&buf, &buflen, dh_p);
+  sftp_msg_write_mpint(&buf, &buflen, dh_g);
 
   /* Client's key */
   sftp_msg_write_mpint(&buf, &buflen, kex->e);
 
   /* Server's key */
-  sftp_msg_write_mpint(&buf, &buflen, kex->dh->pub_key);
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+  DH_get0_key(kex->dh, &dh_pub_key, NULL);
+#else
+  dh_pub_key = kex->dh->pub_key;
+#endif /* prior to OpenSSL-1.1.0 */
+  sftp_msg_write_mpint(&buf, &buflen, dh_pub_key);
 
   /* Shared secret */
   sftp_msg_write_mpint(&buf, &buflen, k);
 
+#if OPENSSL_VERSION_NUMBER >= 0x10100000LL
+  pctx = EVP_MD_CTX_new();
+#else
+  pctx = &ctx;
+#endif /* OpenSSL-1.1.0 and later */
+
   /* In OpenSSL 0.9.6, many of the EVP_Digest* functions returned void, not
    * int.  Without these ugly OpenSSL version preprocessor checks, the
    * compiler will error out with "void value not ignored as it ought to be".
    */
 
 #if OPENSSL_VERSION_NUMBER >= 0x000907000L
-  if (EVP_DigestInit(&ctx, kex->hash) != 1) {
+  if (EVP_DigestInit(pctx, kex->hash) != 1) {
     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
       "error initializing message digest: %s", sftp_crypto_get_errors());
     BN_clear_free(kex->e);
     kex->e = NULL;
     pr_memscrub(ptr, bufsz);
+# if OPENSSL_VERSION_NUMBER >= 0x10100000LL
+    EVP_MD_CTX_free(pctx);
+# endif /* OpenSSL-1.1.0 and later */
     return NULL;
   }
 #else
-  EVP_DigestInit(&ctx, kex->hash);
+  EVP_DigestInit(pctx, kex->hash);
 #endif
 
 #if OPENSSL_VERSION_NUMBER >= 0x000907000L
-  if (EVP_DigestUpdate(&ctx, ptr, (bufsz - buflen)) != 1) {
+  if (EVP_DigestUpdate(pctx, ptr, (bufsz - buflen)) != 1) {
     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
       "error updating message digest: %s", sftp_crypto_get_errors());
     BN_clear_free(kex->e);
     kex->e = NULL;
     pr_memscrub(ptr, bufsz);
+# if OPENSSL_VERSION_NUMBER >= 0x10100000LL
+    EVP_MD_CTX_free(pctx);
+# endif /* OpenSSL-1.1.0 and later */
     return NULL;
   }
 #else
-  EVP_DigestUpdate(&ctx, ptr, (bufsz - buflen));
+  EVP_DigestUpdate(pctx, ptr, (bufsz - buflen));
 #endif
 
 #if OPENSSL_VERSION_NUMBER >= 0x000907000L
-  if (EVP_DigestFinal(&ctx, kex_digest_buf, hlen) != 1) {
+  if (EVP_DigestFinal(pctx, kex_digest_buf, hlen) != 1) {
     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
       "error finalizing message digest: %s", sftp_crypto_get_errors());
     BN_clear_free(kex->e);
     kex->e = NULL;
     pr_memscrub(ptr, bufsz);
+# if OPENSSL_VERSION_NUMBER >= 0x10100000LL
+    EVP_MD_CTX_free(pctx);
+# endif /* OpenSSL-1.1.0 and later */
     return NULL;
   }
 #else
-  EVP_DigestFinal(&ctx, kex_digest_buf, hlen);
+  EVP_DigestFinal(pctx, kex_digest_buf, hlen);
 #endif
 
+# if OPENSSL_VERSION_NUMBER >= 0x10100000LL
+  EVP_MD_CTX_free(pctx);
+# endif /* OpenSSL-1.1.0 and later */
+
   BN_clear_free(kex->e);
   kex->e = NULL;
   pr_memscrub(ptr, bufsz);
@@ -387,7 +449,10 @@ static const unsigned char *calculate_gex_h(struct sftp_kex *kex,
 static const unsigned char *calculate_kexrsa_h(struct sftp_kex *kex,
     const unsigned char *hostkey_data, size_t hostkey_datalen, const BIGNUM *k,
     unsigned char *rsa_key, uint32_t rsa_keylen, uint32_t *hlen) {
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
   EVP_MD_CTX ctx;
+#endif /* prior to OpenSSL-1.1.0 */
+  EVP_MD_CTX *pctx;
   unsigned char *buf, *ptr;
   uint32_t buflen, bufsz;
 
@@ -427,44 +492,63 @@ static const unsigned char *calculate_kexrsa_h(struct sftp_kex *kex,
   /* Shared secret. */
   sftp_msg_write_mpint(&buf, &buflen, k);
 
+#if OPENSSL_VERSION_NUMBER >= 0x10100000LL
+  pctx = EVP_MD_CTX_new();
+#else
+  pctx = &ctx;
+#endif /* OpenSSL-1.1.0 and later */
+
   /* In OpenSSL 0.9.6, many of the EVP_Digest* functions returned void, not
    * int.  Without these ugly OpenSSL version preprocessor checks, the
    * compiler will error out with "void value not ignored as it ought to be".
    */
 
 #if OPENSSL_VERSION_NUMBER >= 0x000907000L
-  if (EVP_DigestInit(&ctx, kex->hash) != 1) {
+  if (EVP_DigestInit(pctx, kex->hash) != 1) {
     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
       "error initializing message digest: %s", sftp_crypto_get_errors());
     pr_memscrub(ptr, bufsz);
+# if OPENSSL_VERSION_NUMBER >= 0x10100000LL
+    EVP_MD_CTX_free(pctx);
+# endif /* OpenSSL-1.1.0 and later */
     return NULL;
   }
 #else
-  EVP_DigestInit(&ctx, kex->hash);
+  EVP_DigestInit(pctx, kex->hash);
 #endif
 
 #if OPENSSL_VERSION_NUMBER >= 0x000907000L
-  if (EVP_DigestUpdate(&ctx, ptr, (bufsz - buflen)) != 1) {
+  if (EVP_DigestUpdate(pctx, ptr, (bufsz - buflen)) != 1) {
     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
       "error updating message digest: %s", sftp_crypto_get_errors());
     pr_memscrub(ptr, bufsz);
+# if OPENSSL_VERSION_NUMBER >= 0x10100000LL
+    EVP_MD_CTX_free(pctx);
+# endif /* OpenSSL-1.1.0 and later */
     return NULL;
   }
 #else
-  EVP_DigestUpdate(&ctx, ptr, (bufsz - buflen));
+  EVP_DigestUpdate(pctx, ptr, (bufsz - buflen));
 #endif
 
 #if OPENSSL_VERSION_NUMBER >= 0x000907000L
-  if (EVP_DigestFinal(&ctx, kex_digest_buf, hlen) != 1) {
+  if (EVP_DigestFinal(pctx, kex_digest_buf, hlen) != 1) {
     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
       "error finalizing message digest: %s", sftp_crypto_get_errors());
     pr_memscrub(ptr, bufsz);
+# if OPENSSL_VERSION_NUMBER >= 0x10100000LL
+    EVP_MD_CTX_free(pctx);
+# endif /* OpenSSL-1.1.0 and later */
     return NULL;
   }
 #else
-  EVP_DigestFinal(&ctx, kex_digest_buf, hlen);
+  EVP_DigestFinal(pctx, kex_digest_buf, hlen);
 #endif
 
+# if OPENSSL_VERSION_NUMBER >= 0x10100000LL
+  EVP_MD_CTX_free(pctx);
+# endif /* OpenSSL-1.1.0 and later */
+
   pr_memscrub(ptr, bufsz);
   return kex_digest_buf;
 }
@@ -473,7 +557,10 @@ static const unsigned char *calculate_kexrsa_h(struct sftp_kex *kex,
 static const unsigned char *calculate_ecdh_h(struct sftp_kex *kex,
     const unsigned char *hostkey_data, size_t hostkey_datalen, const BIGNUM *k,
     uint32_t *hlen) {
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
   EVP_MD_CTX ctx;
+#endif /* prior to OpenSSL-1.1.0 */
+  EVP_MD_CTX *pctx;
   unsigned char *buf, *ptr;
   uint32_t buflen, bufsz;
 
@@ -516,50 +603,69 @@ static const unsigned char *calculate_ecdh_h(struct sftp_kex *kex,
   /* Shared secret */
   sftp_msg_write_mpint(&buf, &buflen, k);
 
+#if OPENSSL_VERSION_NUMBER >= 0x10100000LL
+  pctx = EVP_MD_CTX_new();
+#else
+  pctx = &ctx;
+#endif /* OpenSSL-1.1.0 and later */
+
   /* In OpenSSL 0.9.6, many of the EVP_Digest* functions returned void, not
    * int.  Without these ugly OpenSSL version preprocessor checks, the
    * compiler will error out with "void value not ignored as it ought to be".
    */
 
 #if OPENSSL_VERSION_NUMBER >= 0x000907000L
-  if (EVP_DigestInit(&ctx, kex->hash) != 1) {
+  if (EVP_DigestInit(pctx, kex->hash) != 1) {
     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
       "error initializing message digest: %s", sftp_crypto_get_errors());
     BN_clear_free(kex->e);
     kex->e = NULL;
     pr_memscrub(ptr, bufsz);
+# if OPENSSL_VERSION_NUMBER >= 0x10100000LL
+    EVP_MD_CTX_free(pctx);
+# endif /* OpenSSL-1.1.0 and later */
     return NULL;
   }
 #else
-  EVP_DigestInit(&ctx, kex->hash);
+  EVP_DigestInit(pctx, kex->hash);
 #endif
 
 #if OPENSSL_VERSION_NUMBER >= 0x000907000L
-  if (EVP_DigestUpdate(&ctx, ptr, (bufsz - buflen)) != 1) {
+  if (EVP_DigestUpdate(pctx, ptr, (bufsz - buflen)) != 1) {
     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
       "error updating message digest: %s", sftp_crypto_get_errors());
     BN_clear_free(kex->e);
     kex->e = NULL;
     pr_memscrub(ptr, bufsz);
+# if OPENSSL_VERSION_NUMBER >= 0x10100000LL
+    EVP_MD_CTX_free(pctx);
+# endif /* OpenSSL-1.1.0 and later */
     return NULL;
   }
 #else
-  EVP_DigestUpdate(&ctx, ptr, (bufsz - buflen));
+  EVP_DigestUpdate(pctx, ptr, (bufsz - buflen));
 #endif
 
 #if OPENSSL_VERSION_NUMBER >= 0x000907000L
-  if (EVP_DigestFinal(&ctx, kex_digest_buf, hlen) != 1) {
+  if (EVP_DigestFinal(pctx, kex_digest_buf, hlen) != 1) {
     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
       "error finalizing message digest: %s", sftp_crypto_get_errors());
     BN_clear_free(kex->e);
     kex->e = NULL;
     pr_memscrub(ptr, bufsz);
+# if OPENSSL_VERSION_NUMBER >= 0x10100000LL
+    EVP_MD_CTX_free(pctx);
+# endif /* OpenSSL-1.1.0 and later */
     return NULL;
   }
 #else
-  EVP_DigestFinal(&ctx, kex_digest_buf, hlen);
+  EVP_DigestFinal(pctx, kex_digest_buf, hlen);
 #endif
 
+# if OPENSSL_VERSION_NUMBER >= 0x10100000LL
+  EVP_MD_CTX_free(pctx);
+# endif /* OpenSSL-1.1.0 and later */
+
   BN_clear_free(kex->e);
   kex->e = NULL;
   pr_memscrub(ptr, bufsz);
@@ -572,14 +678,17 @@ static const unsigned char *calculate_ecdh_h(struct sftp_kex *kex,
 static int have_good_dh(DH *dh, BIGNUM *pub_key) {
   register unsigned int i;
   unsigned int nbits = 0;
+  const BIGNUM *dh_p = NULL;
   BIGNUM *tmp;
 
-  if (pub_key->neg) {
+#if OPENSSL_VERSION_NUMBER >= 0x0090801fL
+  if (BN_is_negative(pub_key)) {
     pr_trace_msg(trace_channel, 10,
       "DH public keys cannot have negative numbers");
     errno = EINVAL;
     return -1;
   }
+#endif /* OpenSSL-0.9.8a or later */
 
   if (BN_cmp(pub_key, BN_value_one()) != 1) {
     pr_trace_msg(trace_channel, 10, "bad DH public key exponent (<= 1)");
@@ -587,8 +696,14 @@ static int have_good_dh(DH *dh, BIGNUM *pub_key) {
     return -1;
   }
 
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+  DH_get0_pqg(dh, &dh_p, NULL, NULL);
+#else
+  dh_p = dh->p;
+#endif /* prior to OpenSSL-1.1.0 */
+
   tmp = BN_new();
-  if (!BN_sub(tmp, dh->p, BN_value_one()) ||
+  if (!BN_sub(tmp, dh_p, BN_value_one()) ||
       BN_cmp(pub_key, tmp) != -1) {
     BN_clear_free(tmp);
     pr_trace_msg(trace_channel, 10, "bad DH public key (>= p-1)");
@@ -715,6 +830,7 @@ static int create_dh(struct sftp_kex *kex, int type) {
   }
 
   if (kex->dh) {
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
     if (kex->dh->p) {
       BN_clear_free(kex->dh->p);
       kex->dh->p = NULL;
@@ -734,6 +850,7 @@ static int create_dh(struct sftp_kex *kex, int type) {
       BN_clear_free(kex->dh->pub_key);
       kex->dh->pub_key = NULL;
     }
+#endif /* prior to OpenSSL-1.1.0 */
 
     DH_free(kex->dh);
     kex->dh = NULL;
@@ -743,6 +860,8 @@ static int create_dh(struct sftp_kex *kex, int type) {
 
   /* We have 10 attempts to make a DH key which passes muster. */
   while (attempts <= 10) {
+    BIGNUM *dh_p, *dh_g, *dh_pub_key = NULL, *dh_priv_key = NULL;
+
     pr_signals_handle();
 
     attempts++;
@@ -756,43 +875,64 @@ static int create_dh(struct sftp_kex *kex, int type) {
       return -1;
     }
 
-    dh->p = BN_new();
-    dh->g = BN_new();
-    dh->priv_key = BN_new();
+    dh_p = BN_new();
   
     if (type == SFTP_DH_GROUP1_SHA1) {
-      if (BN_hex2bn(&dh->p, dh_group1_str) == 0) {
+      if (BN_hex2bn(&dh_p, dh_group1_str) == 0) {
         (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
           "error setting DH (group1) P: %s", sftp_crypto_get_errors());
+        BN_clear_free(dh_p);
         DH_free(dh);
         return -1;
       }
 
     } else if (type == SFTP_DH_GROUP14_SHA1) {
-      if (BN_hex2bn(&dh->p, dh_group14_str) == 0) {
+      if (BN_hex2bn(&dh_p, dh_group14_str) == 0) {
         (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
           "error setting DH (group14) P: %s", sftp_crypto_get_errors());
+        BN_clear_free(dh_p);
         DH_free(dh);
         return -1;
       }
     }
 
-    if (BN_hex2bn(&dh->g, "2") == 0) {
+    dh_g = BN_new();
+    if (BN_hex2bn(&dh_g, "2") == 0) {
       (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
         "error setting DH G: %s", sftp_crypto_get_errors());
+      BN_clear_free(dh_p);
+      BN_clear_free(dh_g);
       DH_free(dh);
       return -1;
     }
 
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+    DH_set0_pqg(dh, dh_p, NULL, dh_g);
+#else
+    dh->p = dh_p;
+    dh->g = dh_g;
+#endif /* prior to OpenSSL-1.1.0 */
+
+    dh_priv_key = BN_new();
+
     /* Generate a random private exponent of the desired size, in bits. */
-    if (!BN_rand(dh->priv_key, dh_nbits, 0, 0)) {
+    if (!BN_rand(dh_priv_key, dh_nbits, 0, 0)) {
       (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
         "error generating DH random key (%d bits): %s", dh_nbits,
         sftp_crypto_get_errors());
+      BN_clear_free(dh_priv_key);
       DH_free(dh);
       return -1;
     }
 
+    dh_pub_key = BN_new();
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+    DH_set0_key(dh, dh_pub_key, dh_priv_key);
+#else
+    dh->pub_key = dh_pub_key;
+    dh->priv_key = dh_priv_key;
+#endif /* prior to OpenSSL-1.1.0 */
+
     pr_trace_msg(trace_channel, 12, "generating DH key");
     if (DH_generate_key(dh) != 1) {
       (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
@@ -801,7 +941,13 @@ static int create_dh(struct sftp_kex *kex, int type) {
       return -1;
     }
 
-    if (have_good_dh(dh, dh->pub_key) < 0) {
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+    DH_get0_key(dh, &dh_pub_key, NULL);
+#else
+    dh_pub_key = dh->pub_key;
+#endif /* prior to OpenSSL-1.1.0 */
+
+    if (have_good_dh(dh, dh_pub_key) < 0) {
       DH_free(dh);
       continue;
     }
@@ -825,6 +971,7 @@ static int prepare_dh(struct sftp_kex *kex, int type) {
   }
 
   if (kex->dh) {
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
     if (kex->dh->p) {
       BN_clear_free(kex->dh->p);
       kex->dh->p = NULL;
@@ -844,6 +991,7 @@ static int prepare_dh(struct sftp_kex *kex, int type) {
       BN_clear_free(kex->dh->pub_key);
       kex->dh->pub_key = NULL;
     }
+#endif /* prior to OpenSSL-1.1.0 */
 
     DH_free(kex->dh);
     kex->dh = NULL;
@@ -874,6 +1022,7 @@ static int prepare_dh(struct sftp_kex *kex, int type) {
 static int finish_dh(struct sftp_kex *kex) {
   unsigned int attempts = 0;
   int dh_nbits;
+  BIGNUM *dh_pub_key, *dh_priv_key;
 
   dh_nbits = get_dh_nbits(kex);
 
@@ -885,16 +1034,26 @@ static int finish_dh(struct sftp_kex *kex) {
     pr_trace_msg(trace_channel, 9, "attempt #%u to create a good DH key",
       attempts);
 
-    kex->dh->priv_key = BN_new();
+    dh_priv_key = BN_new();
  
     /* Generate a random private exponent of the desired size, in bits. */ 
-    if (!BN_rand(kex->dh->priv_key, dh_nbits, 0, 0)) {
+    if (!BN_rand(dh_priv_key, dh_nbits, 0, 0)) {
       (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
         "error generating DH random key (%d bits): %s", dh_nbits,
         sftp_crypto_get_errors());
+      BN_clear_free(dh_priv_key);
       return -1;
     }
 
+    dh_pub_key = BN_new();
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+    DH_set0_key(kex->dh, dh_pub_key, dh_priv_key);
+#else
+    kex->dh->pub_key = dh_pub_key;
+    kex->dh->priv_key = dh_priv_key;
+#endif /* prior to OpenSSL-1.1.0 */
+
     pr_trace_msg(trace_channel, 12, "generating DH key");
     if (DH_generate_key(kex->dh) != 1) {
       (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
@@ -903,15 +1062,32 @@ static int finish_dh(struct sftp_kex *kex) {
     }
 
     if (have_good_dh(kex->dh, kex->e) < 0) {
-      if (kex->dh->priv_key) {
-        BN_clear_free(kex->dh->priv_key);
-        kex->dh->priv_key = NULL;
-      } 
+      dh_pub_key = NULL;
+      dh_priv_key = NULL;
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+      DH_get0_key(kex->dh, &dh_pub_key, &dh_priv_key);
+#else
+      dh_pub_key = kex->dh->pub_key;
+      dh_priv_key = kex->dh->priv_key;
+#endif /* prior to OpenSSL-1.1.0 */
+
+      if (dh_priv_key != NULL) {
+        BN_clear_free(dh_priv_key);
+      }
+
+      if (dh_pub_key != NULL) {
+        BN_clear_free(dh_pub_key);
+      }
 
-      if (kex->dh->pub_key) {
-        BN_clear_free(kex->dh->pub_key);
-        kex->dh->pub_key = NULL;
-      } 
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+      /* Per the docs, this is a no-no -- but its the only way to actually
+       * set the public DH key to null.
+       */
+      dh_pub_key = dh_priv_key = NULL;
+#else
+      kex->dh->pub_key = kex->dh->priv_key = NULL;
+#endif /* prior to OpenSSL-1.1.0 */
 
       continue;
     }
@@ -1400,6 +1576,7 @@ static struct sftp_kex *create_kex(pool *p) {
 static void destroy_kex(struct sftp_kex *kex) {
   if (kex) {
     if (kex->dh) {
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
       if (kex->dh->p) {
         BN_clear_free(kex->dh->p);
         kex->dh->p = NULL;
@@ -1409,6 +1586,7 @@ static void destroy_kex(struct sftp_kex *kex) {
         BN_clear_free(kex->dh->g);
         kex->dh->g = NULL;
       }
+#endif /* prior to OpenSSL-1.1.0 */
 
       DH_free(kex->dh);
       kex->dh = NULL;
@@ -2090,9 +2268,13 @@ static int write_kexinit(struct ssh2_packet *pkt, struct sftp_kex *kex) {
    * pseudo-cryptographically secure bytes.
    */
   memset(cookie, 0, sizeof(cookie));
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+  RAND_bytes(cookie, sizeof(cookie));
+#else
   if (RAND_bytes(cookie, sizeof(cookie)) != 1) {
     RAND_pseudo_bytes(cookie, sizeof(cookie));
   }
+#endif /* prior to OpenSSL-1.1.0 */
 
   sftp_msg_write_data(&buf, &buflen, cookie, sizeof(cookie), FALSE);
 
@@ -2286,7 +2468,7 @@ static int write_dh_reply(struct ssh2_packet *pkt, struct sftp_kex *kex) {
   unsigned char *buf, *ptr;
   uint32_t bufsz, buflen, hlen = 0;
   size_t dhlen, hostkey_datalen, hsiglen;
-  BIGNUM *k = NULL;
+  BIGNUM *k = NULL, *dh_pub_key = NULL;
   int res;
 
   /* Compute the shared secret */
@@ -2360,7 +2542,14 @@ static int write_dh_reply(struct ssh2_packet *pkt, struct sftp_kex *kex) {
 
   sftp_msg_write_byte(&buf, &buflen, SFTP_SSH2_MSG_KEX_DH_REPLY);
   sftp_msg_write_data(&buf, &buflen, hostkey_data, hostkey_datalen, TRUE);
-  sftp_msg_write_mpint(&buf, &buflen, kex->dh->pub_key);
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+  DH_get0_key(kex->dh, &dh_pub_key, NULL);
+#else
+  dh_pub_key = kex->dh->pub_key;
+#endif /* prior to OpenSSL-1.1.0 */
+  sftp_msg_write_mpint(&buf, &buflen, dh_pub_key);
+
   sftp_msg_write_data(&buf, &buflen, hsig, hsiglen, TRUE);
 
   /* Scrub any sensitive data when done */
@@ -2642,13 +2831,22 @@ static int get_dh_gex_group(struct sftp_kex *kex, uint32_t min,
       }
 
       if (dh) {
+        BIGNUM *dh_p = NULL, *dh_g = NULL, *dup_p, *dup_g;
+
         pr_trace_msg(trace_channel, 20, "client requested min %lu, pref %lu, "
           "max %lu sizes for DH group exchange, selected DH of %lu bits",
           (unsigned long) min, (unsigned long) pref, (unsigned long) max,
           (unsigned long) DH_size(dh) * 8);
 
-        kex->dh->p = BN_dup(dh->p);
-        if (kex->dh->p == NULL) {
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+        DH_get0_pqg(dh, &dh_p, NULL, &dh_g);
+#else
+        dh_p = dh->p;
+        dh_g = dh->g;
+#endif /* prior to OpenSSL-1.1.0 */
+
+        dup_p = BN_dup(dh_p);
+        if (dup_p == NULL) {
           (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
             "error copying selected DH P: %s", sftp_crypto_get_errors());
           (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
@@ -2656,16 +2854,23 @@ static int get_dh_gex_group(struct sftp_kex *kex, uint32_t min,
           use_fixed_modulus = TRUE;
 
         } else {
-          kex->dh->g = BN_dup(dh->g);
-          if (kex->dh->g == NULL) {
+          dup_g = BN_dup(dh_g);
+          if (dup_g == NULL) {
             (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
               "error copying selected DH G: %s", sftp_crypto_get_errors());
             (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
               "WARNING: using fixed modulus for DH group exchange");
 
-            BN_clear_free(kex->dh->p);
-            kex->dh->p = NULL;
+            BN_clear_free(dup_p);
             use_fixed_modulus = TRUE;
+
+          } else {
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+            DH_set0_pqg(kex->dh, dup_p, NULL, dup_g);
+#else
+            kex->dh->p = dup_p;
+            kex->dh->g = dup_g;
+#endif /* prior to OpenSSL-1.1.0 */
           }
         }
       }
@@ -2702,28 +2907,34 @@ static int get_dh_gex_group(struct sftp_kex *kex, uint32_t min,
   }
 
   if (use_fixed_modulus) {
-    kex->dh->p = BN_new();
-    kex->dh->g = BN_new();
+    BIGNUM *dh_p, *dh_g;
+
+    dh_p = BN_new();
 
-    if (BN_hex2bn(&kex->dh->p, dh_group14_str) == 0) {
+    if (BN_hex2bn(&dh_p, dh_group14_str) == 0) {
       (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
         "error setting DH P: %s", sftp_crypto_get_errors());
-      BN_clear_free(kex->dh->p);
-      kex->dh->p = NULL;
-
+      BN_clear_free(dh_p);
       errno = EACCES;
       return -1;
     }
 
-    if (BN_hex2bn(&kex->dh->g, "2") == 0) {
+    dh_g = BN_new();
+    if (BN_hex2bn(&dh_g, "2") == 0) {
       (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
         "error setting DH G: %s", sftp_crypto_get_errors());
-      BN_clear_free(kex->dh->g);
-      kex->dh->g = NULL;
-
+      BN_clear_free(dh_p);
+      BN_clear_free(dh_g);
       errno = EACCES;
       return -1;
     }
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+    DH_set0_pqg(kex->dh, dh_p, NULL, dh_g);
+#else
+    kex->dh->p = dh_p;
+    kex->dh->g = dh_g;
+#endif /* prior to OpenSSL-1.1.0 */
   }
 
   return 0;
@@ -2731,6 +2942,7 @@ static int get_dh_gex_group(struct sftp_kex *kex, uint32_t min,
 
 static int write_dh_gex_group(struct ssh2_packet *pkt, struct sftp_kex *kex,
     uint32_t min, uint32_t pref, uint32_t max) {
+  BIGNUM *dh_p = NULL, *dh_g = NULL;
   unsigned char *buf, *ptr;
   uint32_t buflen, bufsz;
 
@@ -2743,8 +2955,15 @@ static int write_dh_gex_group(struct ssh2_packet *pkt, struct sftp_kex *kex,
   ptr = buf = palloc(pkt->pool, bufsz);
 
   sftp_msg_write_byte(&buf, &buflen, SFTP_SSH2_MSG_KEX_DH_GEX_GROUP);
-  sftp_msg_write_mpint(&buf, &buflen, kex->dh->p);
-  sftp_msg_write_mpint(&buf, &buflen, kex->dh->g);
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+  DH_get0_pqg(kex->dh, &dh_p, NULL, &dh_g);
+#else
+  dh_p = kex->dh->p;
+  dh_g = kex->dh->g;
+#endif /* prior to OpenSSL-1.1.0 */
+  sftp_msg_write_mpint(&buf, &buflen, dh_p);
+  sftp_msg_write_mpint(&buf, &buflen, dh_g);
 
   pkt->payload = ptr;
   pkt->payload_len = (bufsz - buflen);
@@ -2776,7 +2995,7 @@ static int write_dh_gex_reply(struct ssh2_packet *pkt, struct sftp_kex *kex,
   unsigned char *buf, *ptr;
   uint32_t bufsz, buflen, hlen = 0;
   size_t dhlen, hostkey_datalen, hsiglen;
-  BIGNUM *k = NULL;
+  BIGNUM *k = NULL, *dh_pub_key = NULL;
   int res;
 
   /* Compute the shared secret. */
@@ -2855,7 +3074,14 @@ static int write_dh_gex_reply(struct ssh2_packet *pkt, struct sftp_kex *kex,
 
   sftp_msg_write_byte(&buf, &buflen, SFTP_SSH2_MSG_KEX_DH_GEX_REPLY);
   sftp_msg_write_data(&buf, &buflen, hostkey_data, hostkey_datalen, TRUE);
-  sftp_msg_write_mpint(&buf, &buflen, kex->dh->pub_key);
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+  DH_get0_key(kex->dh, &dh_pub_key, NULL);
+#else
+  dh_pub_key = kex->dh->pub_key;
+#endif /* prior to OpenSSL-1.1.0 */
+  sftp_msg_write_mpint(&buf, &buflen, dh_pub_key);
+
   sftp_msg_write_data(&buf, &buflen, hsig, hsiglen, TRUE);
 
   /* Scrub any sensitive data when done */
@@ -3018,6 +3244,7 @@ static int read_kexrsa_secret(struct ssh2_packet *pkt, struct sftp_kex *kex) {
 }
 
 static int write_kexrsa_pubkey(struct ssh2_packet *pkt, struct sftp_kex *kex) {
+  BIGNUM *rsa_n = NULL, *rsa_e = NULL;
   unsigned char *buf, *ptr, *buf2, *ptr2;
   const unsigned char *hostkey_data;
   uint32_t buflen, bufsz, buflen2, bufsz2, hostkey_datalen;
@@ -3040,8 +3267,15 @@ static int write_kexrsa_pubkey(struct ssh2_packet *pkt, struct sftp_kex *kex) {
    * written in its entirety as an SSH2 string.
    */
   sftp_msg_write_string(&buf, &buflen, "ssh-rsa");
-  sftp_msg_write_mpint(&buf, &buflen, kex->rsa->e);
-  sftp_msg_write_mpint(&buf, &buflen, kex->rsa->n);
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+  RSA_get0_key(kex->rsa, &rsa_n, &rsa_e, NULL);
+#else
+  rsa_e = kex->rsa->e;
+  rsa_n = kex->rsa->n;
+#endif /* prior to OpenSSL-1.1.0 */
+  sftp_msg_write_mpint(&buf, &buflen, rsa_e);
+  sftp_msg_write_mpint(&buf, &buflen, rsa_n);
 
   /* XXX Is this buffer large enough?  Too large? */
   bufsz2 = buflen2 = 4096;
@@ -3060,6 +3294,7 @@ static int write_kexrsa_pubkey(struct ssh2_packet *pkt, struct sftp_kex *kex) {
 }
 
 static int write_kexrsa_done(struct ssh2_packet *pkt, struct sftp_kex *kex) {
+  BIGNUM *rsa_e = NULL, *rsa_n = NULL;
   unsigned char *buf, *ptr, *buf2, *ptr2;
   const unsigned char *h, *hostkey_data, *hsig;
   uint32_t buflen, bufsz, buflen2, bufsz2, hlen;
@@ -3090,8 +3325,15 @@ static int write_kexrsa_done(struct ssh2_packet *pkt, struct sftp_kex *kex) {
    * written in its entirety as an SSH2 string.
    */
   sftp_msg_write_string(&buf2, &buflen2, "ssh-rsa");
-  sftp_msg_write_mpint(&buf2, &buflen2, kex->rsa->e);
-  sftp_msg_write_mpint(&buf2, &buflen2, kex->rsa->n);
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+  RSA_get0_key(kex->rsa, &rsa_n, &rsa_e, NULL);
+#else
+  rsa_e = kex->rsa->e;
+  rsa_n = kex->rsa->n;
+#endif /* prior to OpenSSL-1.1.0 */
+  sftp_msg_write_mpint(&buf2, &buflen2, rsa_e);
+  sftp_msg_write_mpint(&buf2, &buflen2, rsa_n);
 
   /* Calculate H */
   h = calculate_kexrsa_h(kex, hostkey_data, hostkey_datalen, kex->k,
diff --git a/contrib/mod_sftp/keys.c b/contrib/mod_sftp/keys.c
index 371de28..c448341 100644
--- a/contrib/mod_sftp/keys.c
+++ b/contrib/mod_sftp/keys.c
@@ -1,6 +1,6 @@
 /*
  * ProFTPD - mod_sftp key mgmt (keys)
- * Copyright (c) 2008-2015 TJ Saunders
+ * Copyright (c) 2008-2016 TJ Saunders
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -789,6 +789,7 @@ static EVP_PKEY *get_pkey_from_data(pool *p, unsigned char *pkey_data,
 
   if (strncmp(pkey_type, "ssh-rsa", 8) == 0) {
     RSA *rsa;
+    BIGNUM *rsa_e = NULL, *rsa_n = NULL;
 
     pkey = EVP_PKEY_new();
     if (pkey == NULL) {
@@ -805,8 +806,15 @@ static EVP_PKEY *get_pkey_from_data(pool *p, unsigned char *pkey_data,
       return NULL;
     }
 
-    rsa->e = sftp_msg_read_mpint(p, &pkey_data, &pkey_datalen);
-    rsa->n = sftp_msg_read_mpint(p, &pkey_data, &pkey_datalen);
+    rsa_e = sftp_msg_read_mpint(p, &pkey_data, &pkey_datalen);
+    rsa_n = sftp_msg_read_mpint(p, &pkey_data, &pkey_datalen);
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+    RSA_set0_key(rsa, rsa_n, rsa_e, NULL);
+#else
+    rsa->e = rsa_e;
+    rsa->n = rsa_n;
+#endif /* prior to OpenSSL-1.1.0 */
 
     if (EVP_PKEY_assign_RSA(pkey, rsa) != 1) {
       (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
@@ -818,6 +826,7 @@ static EVP_PKEY *get_pkey_from_data(pool *p, unsigned char *pkey_data,
 
   } else if (strncmp(pkey_type, "ssh-dss", 8) == 0) {
     DSA *dsa;
+    BIGNUM *dsa_p, *dsa_q, *dsa_g, *dsa_pub_key;
 
     pkey = EVP_PKEY_new();
     if (pkey == NULL) {
@@ -834,10 +843,20 @@ static EVP_PKEY *get_pkey_from_data(pool *p, unsigned char *pkey_data,
       return NULL;
     }
 
-    dsa->p = sftp_msg_read_mpint(p, &pkey_data, &pkey_datalen);
-    dsa->q = sftp_msg_read_mpint(p, &pkey_data, &pkey_datalen);
-    dsa->g = sftp_msg_read_mpint(p, &pkey_data, &pkey_datalen);
-    dsa->pub_key = sftp_msg_read_mpint(p, &pkey_data, &pkey_datalen);
+    dsa_p = sftp_msg_read_mpint(p, &pkey_data, &pkey_datalen);
+    dsa_q = sftp_msg_read_mpint(p, &pkey_data, &pkey_datalen);
+    dsa_g = sftp_msg_read_mpint(p, &pkey_data, &pkey_datalen);
+    dsa_pub_key = sftp_msg_read_mpint(p, &pkey_data, &pkey_datalen);
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+    DSA_set0_pqg(dsa, dsa_p, dsa_q, dsa_g);
+    DSA_set0_key(dsa, dsa_pub_key, NULL);
+#else
+    dsa->p = dsa_p;
+    dsa->q = dsa_q;
+    dsa->g = dsa_g;
+    dsa->pub_key = dsa_pub_key;
+#endif /* prior to OpenSSL-1.1.0 */
 
     if (EVP_PKEY_assign_DSA(pkey, dsa) != 1) {
       (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
@@ -1280,6 +1299,18 @@ int sftp_keys_validate_ecdsa_params(const EC_GROUP *group,
 }
 #endif /* PR_USE_OPENSSL_ECC */
 
+static int get_pkey_type(EVP_PKEY *pkey) {
+  int pkey_type;
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+  pkey_type = EVP_PKEY_id(pkey);
+#else
+  pkey_type = EVP_PKEY_type(pkey->type);
+#endif /* OpenSSL 1.1.x and later */
+
+  return pkey_type;
+}
+
 /* Compare a "blob" of pubkey data sent by the client for authentication
  * with a file pubkey (from an RFC4716 formatted file).  Returns -1 if
  * there was an error, TRUE if the keys are equals, and FALSE if not.
@@ -1307,22 +1338,34 @@ int sftp_keys_compare_keys(pool *p, unsigned char *client_pubkey_data,
     return -1;
   }
 
-  if (EVP_PKEY_type(client_pkey->type) == EVP_PKEY_type(file_pkey->type)) {
-    switch (EVP_PKEY_type(client_pkey->type)) {
+  if (get_pkey_type(client_pkey) == get_pkey_type(file_pkey)) {
+    switch (get_pkey_type(client_pkey)) {
       case EVP_PKEY_RSA: {
-        RSA *client_rsa, *file_rsa;
+        RSA *remote_rsa = NULL, *local_rsa = NULL;
+        BIGNUM *remote_rsa_e = NULL, *local_rsa_e = NULL;
+        BIGNUM *remote_rsa_n = NULL, *local_rsa_n = NULL;
+
+        remote_rsa = EVP_PKEY_get1_RSA(client_pkey);
+        local_rsa = EVP_PKEY_get1_RSA(file_pkey);
 
-        client_rsa = EVP_PKEY_get1_RSA(client_pkey);
-        file_rsa = EVP_PKEY_get1_RSA(file_pkey);
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+        RSA_get0_key(remote_rsa, &remote_rsa_n, &remote_rsa_e, NULL);
+        RSA_get0_key(local_rsa, &local_rsa_n, &local_rsa_e, NULL);
+#else
+        remote_rsa_e = remote_rsa->e;
+        local_rsa_e = local_rsa->e;
+        remote_rsa_n = remote_rsa->n;
+        local_rsa_n = local_rsa->n;
+#endif /* prior to OpenSSL-1.1.0 */
 
-        if (BN_cmp(client_rsa->e, file_rsa->e) != 0) {
+        if (BN_cmp(remote_rsa_e, local_rsa_e) != 0) {
           pr_trace_msg(trace_channel, 17, "%s",
             "RSA key mismatch: client-sent RSA key component 'e' does not "
             "match local RSA key component 'e'");
           res = FALSE;
 
         } else {
-          if (BN_cmp(client_rsa->n, file_rsa->n) != 0) {
+          if (BN_cmp(remote_rsa_n, local_rsa_n) != 0) {
             pr_trace_msg(trace_channel, 17, "%s",
               "RSA key mismatch: client-sent RSA key component 'n' does not "
               "match local RSA key component 'n'");
@@ -1333,39 +1376,58 @@ int sftp_keys_compare_keys(pool *p, unsigned char *client_pubkey_data,
           }
         } 
 
-        RSA_free(client_rsa);
-        RSA_free(file_rsa);
+        RSA_free(local_rsa);
+        RSA_free(remote_rsa);
         break;
       }
 
       case EVP_PKEY_DSA: {
-        DSA *client_dsa, *file_dsa;
-
-        client_dsa = EVP_PKEY_get1_DSA(client_pkey);
-        file_dsa = EVP_PKEY_get1_DSA(file_pkey);
-
-        if (BN_cmp(client_dsa->p, file_dsa->p) != 0) {
+        DSA *remote_dsa = NULL, *local_dsa = NULL;
+        BIGNUM *remote_dsa_p, *remote_dsa_q, *remote_dsa_g;
+        BIGNUM *local_dsa_p, *local_dsa_q, *local_dsa_g;
+        BIGNUM *remote_dsa_pub_key, *local_dsa_pub_key;
+
+        local_dsa = EVP_PKEY_get1_DSA(client_pkey);
+        remote_dsa = EVP_PKEY_get1_DSA(file_pkey);
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+        DSA_get0_pqg(remote_dsa, &remote_dsa_p, &remote_dsa_q, &remote_dsa_g);
+        DSA_get0_pqg(local_dsa, &local_dsa_p, &local_dsa_q, &local_dsa_g);
+        DSA_get0_key(remote_dsa, &remote_dsa_pub_key, NULL);
+        DSA_get0_key(local_dsa, &local_dsa_pub_key, NULL);
+#else
+        remote_dsa_p = remote_dsa->p;
+        remote_dsa_q = remote_dsa->q;
+        remote_dsa_g = remote_dsa->g;
+        remote_dsa_pub_key = remote_dsa->pub_key;
+        local_dsa_p = local_dsa->p;
+        local_dsa_q = local_dsa->q;
+        local_dsa_g = local_dsa->g;
+        local_dsa_pub_key = local_dsa->pub_key;
+#endif /* prior to OpenSSL-1.1.0 */
+
+        if (BN_cmp(remote_dsa_p, local_dsa_p) != 0) {
           pr_trace_msg(trace_channel, 17, "%s",
             "DSA key mismatch: client-sent DSA key parameter 'p' does not "
             "match local DSA key parameter 'p'");
           res = FALSE;
 
         } else {
-          if (BN_cmp(client_dsa->q, file_dsa->q) != 0) {
+          if (BN_cmp(remote_dsa_q, local_dsa_q) != 0) {
             pr_trace_msg(trace_channel, 17, "%s",
               "DSA key mismatch: client-sent DSA key parameter 'q' does not "
               "match local DSA key parameter 'q'");
             res = FALSE;
 
           } else {
-            if (BN_cmp(client_dsa->g, file_dsa->g) != 0) {
+            if (BN_cmp(remote_dsa_g, local_dsa_g) != 0) {
               pr_trace_msg(trace_channel, 17, "%s",
                 "DSA key mismatch: client-sent DSA key parameter 'g' does not "
                 "match local DSA key parameter 'g'");
               res = FALSE;
 
             } else {
-              if (BN_cmp(client_dsa->pub_key, file_dsa->pub_key) != 0) {
+              if (BN_cmp(remote_dsa_pub_key, local_dsa_pub_key) != 0) {
                 pr_trace_msg(trace_channel, 17, "%s",
                   "DSA key mismatch: client-sent DSA key parameter 'pub_key' "
                   "does not match local DSA key parameter 'pub_key'");
@@ -1378,8 +1440,8 @@ int sftp_keys_compare_keys(pool *p, unsigned char *client_pubkey_data,
           }
         }
 
-        DSA_free(client_dsa);
-        DSA_free(file_dsa);
+        DSA_free(remote_dsa);
+        DSA_free(local_dsa);
 
         break;
       }
@@ -1422,7 +1484,7 @@ int sftp_keys_compare_keys(pool *p, unsigned char *client_pubkey_data,
       default:
         (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
           "unable to compare %s keys: unsupported key type",
-          get_key_type_desc(EVP_PKEY_type(client_pkey->type)));
+          get_key_type_desc(get_pkey_type(client_pkey)));
         errno = ENOSYS;
         break;
     }
@@ -1431,8 +1493,8 @@ int sftp_keys_compare_keys(pool *p, unsigned char *client_pubkey_data,
     if (pr_trace_get_level(trace_channel) >= 17) {
       const char *client_key_desc, *file_key_desc;
 
-      client_key_desc = get_key_type_desc(EVP_PKEY_type(client_pkey->type));
-      file_key_desc = get_key_type_desc(EVP_PKEY_type(file_pkey->type));
+      client_key_desc = get_key_type_desc(get_pkey_type(client_pkey));
+      file_key_desc = get_key_type_desc(get_pkey_type(file_pkey));
 
       pr_trace_msg(trace_channel, 17, "key mismatch: cannot compare %s key "
         "(client-sent) with %s key (local)", client_key_desc, file_key_desc);
@@ -1449,7 +1511,10 @@ int sftp_keys_compare_keys(pool *p, unsigned char *client_pubkey_data,
 
 const char *sftp_keys_get_fingerprint(pool *p, unsigned char *key_data,
     uint32_t key_datalen, int digest_algo) {
-  EVP_MD_CTX fp_ctx;
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+  EVP_MD_CTX ctx;
+#endif /* prior to OpenSSL-1.1.0 */
+  EVP_MD_CTX *pctx;
   const EVP_MD *digest;
   char *digest_name = "none", *fp;
   unsigned char *fp_data;
@@ -1474,47 +1539,63 @@ const char *sftp_keys_get_fingerprint(pool *p, unsigned char *key_data,
       return NULL;
   }
 
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+  pctx = EVP_MD_CTX_new();
+#else
+  pctx = &ctx;
+#endif /* prior to OpenSSL-1.1.0 */
+
   /* In OpenSSL 0.9.6, many of the EVP_Digest* functions returned void, not
    * int.  Without these ugly OpenSSL version preprocessor checks, the
    * compiler will error out with "void value not ignored as it ought to be".
    */
 
 #if OPENSSL_VERSION_NUMBER >= 0x000907000L
-  if (EVP_DigestInit(&fp_ctx, digest) != 1) {
+  if (EVP_DigestInit(pctx, digest) != 1) {
     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
       "error initializing %s digest: %s", digest_name,
       sftp_crypto_get_errors());
+# if OPENSSL_VERSION_NUMBER >= 0x10100000L
+    EVP_MD_CTX_free(pctx);
+# endif /* OpenSSL-1.1.0 and later */
     errno = EPERM;
     return NULL;
   }
 #else
-  EVP_DigestInit(&fp_ctx, digest);
+  EVP_DigestInit(pctx, digest);
 #endif
 
 #if OPENSSL_VERSION_NUMBER >= 0x000907000L
-  if (EVP_DigestUpdate(&fp_ctx, key_data, key_datalen) != 1) {
+  if (EVP_DigestUpdate(pctx, key_data, key_datalen) != 1) {
     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
       "error updating %s digest: %s", digest_name, sftp_crypto_get_errors());
+# if OPENSSL_VERSION_NUMBER >= 0x10100000L
+    EVP_MD_CTX_free(pctx);
+# endif /* OpenSSL-1.1.0 and later */
     errno = EPERM;
     return NULL;
   }
 #else
-  EVP_DigestUpdate(&fp_ctx, key_data, key_datalen);
+  EVP_DigestUpdate(pctx, key_data, key_datalen);
 #endif
 
   fp_data = palloc(p, EVP_MAX_MD_SIZE);
 
 #if OPENSSL_VERSION_NUMBER >= 0x000907000L
-  if (EVP_DigestFinal(&fp_ctx, fp_data, &fp_datalen) != 1) {
+  if (EVP_DigestFinal(pctx, fp_data, &fp_datalen) != 1) {
     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
       "error finishing %s digest: %s", digest_name, sftp_crypto_get_errors());
     errno = EPERM;
     return NULL;
   }
 #else
-  EVP_DigestFinal(&fp_ctx, fp_data, &fp_datalen);
+  EVP_DigestFinal(pctx, fp_data, &fp_datalen);
 #endif
 
+# if OPENSSL_VERSION_NUMBER >= 0x10100000L
+  EVP_MD_CTX_free(pctx);
+# endif /* OpenSSL-1.1.0 and later */
+
   /* Now encode that digest in fp_data as hex characters. */
   fp = "";
 
@@ -1614,7 +1695,7 @@ static int handle_hostkey(pool *p, EVP_PKEY *pkey,
     const unsigned char *key_data, uint32_t key_datalen,
     const char *file_path, const char *agent_path) {
 
-  switch (pkey->type) {
+  switch (get_pkey_type(pkey)) {
     case EVP_PKEY_RSA: {
 #if OPENSSL_VERSION_NUMBER < 0x0090702fL
       /* In OpenSSL-0.9.7a and later, RSA blinding is turned on by default.
@@ -1842,7 +1923,7 @@ static int handle_hostkey(pool *p, EVP_PKEY *pkey,
 
     default:
       (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
-        "unknown private key type (%d), ignoring", pkey->type);
+        "unknown private key type (%d), ignoring", get_pkey_type(pkey));
       EVP_PKEY_free(pkey);
       return -1;
   }
@@ -2012,6 +2093,7 @@ const unsigned char *sftp_keys_get_hostkey_data(pool *p,
   switch (key_type) {
     case SFTP_KEY_RSA: {
       RSA *rsa;
+      BIGNUM *rsa_n = NULL, *rsa_e = NULL;
 
       rsa = EVP_PKEY_get1_RSA(sftp_rsa_hostkey->pkey);
       if (rsa == NULL) {
@@ -2023,8 +2105,15 @@ const unsigned char *sftp_keys_get_hostkey_data(pool *p,
       /* XXX Is this buffer large enough?  Too large? */
       ptr = buf = palloc(p, buflen);
       sftp_msg_write_string(&buf, &buflen, "ssh-rsa");
-      sftp_msg_write_mpint(&buf, &buflen, rsa->e);
-      sftp_msg_write_mpint(&buf, &buflen, rsa->n);
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+      RSA_get0_key(rsa, &rsa_n, &rsa_e, NULL);
+#else
+      rsa_e = rsa->e;
+      rsa_n = rsa->n;
+#endif /* prior to OpenSSL-1.1.0 */
+      sftp_msg_write_mpint(&buf, &buflen, rsa_e);
+      sftp_msg_write_mpint(&buf, &buflen, rsa_n);
 
       RSA_free(rsa);
       break;
@@ -2032,6 +2121,7 @@ const unsigned char *sftp_keys_get_hostkey_data(pool *p,
 
     case SFTP_KEY_DSA: {
       DSA *dsa;
+      BIGNUM *dsa_p = NULL, *dsa_q = NULL, *dsa_g = NULL, *dsa_pub_key = NULL;
 
       dsa = EVP_PKEY_get1_DSA(sftp_dsa_hostkey->pkey);
       if (dsa == NULL) {
@@ -2043,10 +2133,20 @@ const unsigned char *sftp_keys_get_hostkey_data(pool *p,
       /* XXX Is this buffer large enough?  Too large? */
       ptr = buf = palloc(p, buflen);
       sftp_msg_write_string(&buf, &buflen, "ssh-dss");
-      sftp_msg_write_mpint(&buf, &buflen, dsa->p);
-      sftp_msg_write_mpint(&buf, &buflen, dsa->q);
-      sftp_msg_write_mpint(&buf, &buflen, dsa->g);
-      sftp_msg_write_mpint(&buf, &buflen, dsa->pub_key);
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+      DSA_get0_pqg(dsa, &dsa_p, &dsa_q, &dsa_g);
+      DSA_get0_key(dsa, &dsa_pub_key, NULL);
+#else
+      dsa_p = dsa->p;
+      dsa_q = dsa->q;
+      dsa_g = dsa->g;
+      dsa_pub_key = dsa->pub_key;;
+#endif /* prior to OpenSSL-1.1.0 */
+      sftp_msg_write_mpint(&buf, &buflen, dsa_p);
+      sftp_msg_write_mpint(&buf, &buflen, dsa_q);
+      sftp_msg_write_mpint(&buf, &buflen, dsa_g);
+      sftp_msg_write_mpint(&buf, &buflen, dsa_pub_key);
 
       DSA_free(dsa);
       break;
@@ -2252,7 +2352,10 @@ static const unsigned char *agent_sign_data(pool *p, const char *agent_path,
 static const unsigned char *rsa_sign_data(pool *p, const unsigned char *data,
     size_t datalen, size_t *siglen) {
   RSA *rsa;
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
   EVP_MD_CTX ctx;
+#endif /* prior to OpenSSL-1.1.0 */
+  EVP_MD_CTX *pctx;
   const EVP_MD *sha1 = EVP_sha1();
   unsigned char dgst[EVP_MAX_MD_SIZE], *sig_data;
   unsigned char *buf, *ptr;
@@ -2273,9 +2376,19 @@ static const unsigned char *rsa_sign_data(pool *p, const unsigned char *data,
     return NULL;
   }
 
-  EVP_DigestInit(&ctx, sha1);
-  EVP_DigestUpdate(&ctx, data, datalen);
-  EVP_DigestFinal(&ctx, dgst, &dgstlen);
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+  pctx = EVP_MD_CTX_new();
+#else
+  pctx = &ctx;
+#endif /* prior to OpenSSL-1.1.0 */
+
+  EVP_DigestInit(pctx, sha1);
+  EVP_DigestUpdate(pctx, data, datalen);
+  EVP_DigestFinal(pctx, dgst, &dgstlen);
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+  EVP_MD_CTX_free(pctx);
+#endif /* OpenSSL-1.1.0 and later */
 
   sig_rsalen = RSA_size(rsa);
   sig_data = pcalloc(p, sig_rsalen);
@@ -2324,7 +2437,11 @@ static const unsigned char *dsa_sign_data(pool *p, const unsigned char *data,
     size_t datalen, size_t *siglen) {
   DSA *dsa;
   DSA_SIG *sig;
+  BIGNUM *sig_r = NULL, *sig_s = NULL;
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
   EVP_MD_CTX ctx;
+#endif /* prior to OpenSSL-1.1.0 */
+  EVP_MD_CTX *pctx;
   const EVP_MD *sha1 = EVP_sha1();
   unsigned char dgst[EVP_MAX_MD_SIZE], *sig_data;
   unsigned char *buf, *ptr;
@@ -2345,9 +2462,19 @@ static const unsigned char *dsa_sign_data(pool *p, const unsigned char *data,
     return NULL;
   }
 
-  EVP_DigestInit(&ctx, sha1);
-  EVP_DigestUpdate(&ctx, data, datalen);
-  EVP_DigestFinal(&ctx, dgst, &dgstlen);
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+  pctx = EVP_MD_CTX_new();
+#else
+  pctx = &ctx;
+#endif /* prior to OpenSSL-1.1.0 */
+
+  EVP_DigestInit(pctx, sha1);
+  EVP_DigestUpdate(pctx, data, datalen);
+  EVP_DigestFinal(pctx, dgst, &dgstlen);
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+  EVP_MD_CTX_free(pctx);
+#endif /* OpenSSL-1.1.0 and later */
 
   sig = DSA_do_sign(dgst, dgstlen, dsa);
   if (sig == NULL) {
@@ -2361,8 +2488,15 @@ static const unsigned char *dsa_sign_data(pool *p, const unsigned char *data,
   /* Got the signature, no need for the digest memory. */
   pr_memscrub(dgst, dgstlen);
 
-  rlen = BN_num_bytes(sig->r);
-  slen = BN_num_bytes(sig->s);
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+  DSA_SIG_get0(&sig_r, &sig_s, sig);
+#else
+  sig_r = sig->r;
+  sig_s = sig->s;
+#endif /* prior to OpenSSL-1.1.0 */
+
+  rlen = BN_num_bytes(sig_r);
+  slen = BN_num_bytes(sig_s);
 
   /* Make sure the values of R and S are big enough. */
   if (rlen > SFTP_DSA_INTEGER_LEN ||
@@ -2380,9 +2514,9 @@ static const unsigned char *dsa_sign_data(pool *p, const unsigned char *data,
    * ensure the correct placement of the R and S values in the signature,
    * per RFC 4253 Section 6.6 requirements.
    */
-  BN_bn2bin(sig->r,
+  BN_bn2bin(sig_r,
     sig_data + SFTP_DSA_SIGNATURE_LEN - SFTP_DSA_INTEGER_LEN - rlen);
-  BN_bn2bin(sig->s, sig_data + SFTP_DSA_SIGNATURE_LEN - slen);
+  BN_bn2bin(sig_s, sig_data + SFTP_DSA_SIGNATURE_LEN - slen);
 
   /* Done with the signature. */
   DSA_SIG_free(sig);
@@ -2409,7 +2543,11 @@ static const unsigned char *ecdsa_sign_data(pool *p, const unsigned char *data,
     size_t datalen, size_t *siglen, int nid) {
   EC_KEY *ec = NULL;
   ECDSA_SIG *sig;
+  BIGNUM *sig_r = NULL, *sig_s = NULL;
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
   EVP_MD_CTX ctx;
+#endif /* prior to OpenSSL-1.1.0 */
+  EVP_MD_CTX *pctx;
   const EVP_MD *md;
   unsigned char dgst[EVP_MAX_MD_SIZE];
   unsigned char *buf, *ptr, *sig_buf, *sig_ptr;
@@ -2476,9 +2614,19 @@ static const unsigned char *ecdsa_sign_data(pool *p, const unsigned char *data,
   buflen = bufsz = SFTP_MAX_SIG_SZ;
   ptr = buf = sftp_msg_getbuf(p, bufsz);
 
-  EVP_DigestInit(&ctx, md);
-  EVP_DigestUpdate(&ctx, data, datalen);
-  EVP_DigestFinal(&ctx, dgst, &dgstlen);
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+  pctx = EVP_MD_CTX_new();
+#else
+  pctx = &ctx;
+#endif /* prior to OpenSSL-1.1.0 */
+
+  EVP_DigestInit(pctx, md);
+  EVP_DigestUpdate(pctx, data, datalen);
+  EVP_DigestFinal(pctx, dgst, &dgstlen);
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+  EVP_MD_CTX_free(pctx);
+#endif /* OpenSSL-1.1.0 and later */
 
   sig = ECDSA_do_sign(dgst, dgstlen, ec);
   if (sig == NULL) {
@@ -2496,12 +2644,19 @@ static const unsigned char *ecdsa_sign_data(pool *p, const unsigned char *data,
    * selected, so we do no sanity checking of their lengths.
    */
 
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+  ECDSA_SIG_get0(&sig_r, &sig_s, sig);
+#else
+  sig_r = sig->r;
+  sig_s = sig->s;
+#endif /* prior to OpenSSL-1.1.0 */
+
   /* XXX Is this buffer large enough?  Too large? */
   sig_buflen = sig_bufsz = 256;
   sig_ptr = sig_buf = palloc(p, sig_bufsz);
 
-  sftp_msg_write_mpint(&sig_buf, &sig_buflen, sig->r);
-  sftp_msg_write_mpint(&sig_buf, &sig_buflen, sig->s);
+  sftp_msg_write_mpint(&sig_buf, &sig_buflen, sig_r);
+  sftp_msg_write_mpint(&sig_buf, &sig_buflen, sig_s);
 
   /* Done with the signature. */
   ECDSA_SIG_free(sig);
@@ -2600,18 +2755,18 @@ int sftp_keys_verify_pubkey_type(pool *p, unsigned char *pubkey_data,
 
   switch (pubkey_type) {
     case SFTP_KEY_RSA:
-      res = (EVP_PKEY_type(pkey->type) == EVP_PKEY_RSA); 
+      res = (get_pkey_type(pkey) == EVP_PKEY_RSA); 
       break;
 
     case SFTP_KEY_DSA:
-      res = (EVP_PKEY_type(pkey->type) == EVP_PKEY_DSA); 
+      res = (get_pkey_type(pkey) == EVP_PKEY_DSA); 
       break;
 
 #ifdef PR_USE_OPENSSL_ECC
     case SFTP_KEY_ECDSA_256:
     case SFTP_KEY_ECDSA_384:
     case SFTP_KEY_ECDSA_521:
-      if (EVP_PKEY_type(pkey->type) == EVP_PKEY_EC) {
+      if (get_pkey_type(pkey) == EVP_PKEY_EC) {
         EC_KEY *ec;
         int ec_nid;
 
@@ -2652,7 +2807,10 @@ int sftp_keys_verify_signed_data(pool *p, const char *pubkey_algo,
     unsigned char *signature, uint32_t signaturelen,
     unsigned char *sig_data, size_t sig_datalen) {
   EVP_PKEY *pkey;
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
   EVP_MD_CTX ctx;
+#endif /* prior to OpenSSL-1.1.0 */
+  EVP_MD_CTX *pctx;
   unsigned char *sig;
   uint32_t sig_len;
   unsigned char digest[EVP_MAX_MD_SIZE];
@@ -2725,9 +2883,19 @@ int sftp_keys_verify_signed_data(pool *p, const char *pubkey_algo,
       sig_len = (uint32_t) modulus_len;
     }
 
-    EVP_DigestInit(&ctx, EVP_sha1());
-    EVP_DigestUpdate(&ctx, sig_data, sig_datalen);
-    EVP_DigestFinal(&ctx, digest, &digestlen);
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+      pctx = EVP_MD_CTX_new();
+#else
+      pctx = &ctx;
+#endif /* prior to OpenSSL-1.1.0 */
+
+    EVP_DigestInit(pctx, EVP_sha1());
+    EVP_DigestUpdate(pctx, sig_data, sig_datalen);
+    EVP_DigestFinal(pctx, digest, &digestlen);
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+      EVP_MD_CTX_free(pctx);
+#endif /* OpenSSL-1.1.0 and later */
 
     ok = RSA_verify(NID_sha1, digest, digestlen, sig, sig_len, rsa);
     if (ok == 1) {
@@ -2744,6 +2912,7 @@ int sftp_keys_verify_signed_data(pool *p, const char *pubkey_algo,
   } else if (strncmp(sig_type, "ssh-dss", 8) == 0) {
     DSA *dsa;
     DSA_SIG *dsa_sig;
+    BIGNUM *sig_r, *sig_s;
     int ok;
 
     dsa = EVP_PKEY_get1_DSA(pkey);
@@ -2761,26 +2930,57 @@ int sftp_keys_verify_signed_data(pool *p, const char *pubkey_algo,
       sig_len);
 
     dsa_sig = DSA_SIG_new();
-    dsa_sig->r = BN_new();
-    dsa_sig->s = BN_new();
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+    DSA_SIG_get0(&sig_r, &sig_s, dsa_sig);
+#else
+    sig_r = dsa_sig->r;
+    sig_s = dsa_sig->s;
+#endif /* prior to OpenSSL-1.1.0 */
 
-    if (BN_bin2bn(sig, 20, dsa_sig->r) == NULL) {
+    sig_r = BN_bin2bn(sig, 20, sig_r);
+    if (sig_r == NULL) {
       (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
         "error obtaining 'r' DSA signature component: %s",
         sftp_crypto_get_errors());
+      DSA_free(dsa);
+      DSA_SIG_free(dsa_sig);
       res = -1;
     }
 
-    if (BN_bin2bn(sig + 20, 20, dsa_sig->s) == NULL) {
+    sig_s = BN_bin2bn(sig + 20, 20, sig_s);
+    if (sig_s == NULL) {
       (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
         "error obtaining 's' DSA signature component: %s",
         sftp_crypto_get_errors());
+      DSA_free(dsa);
+      DSA_SIG_free(dsa_sig);
       res = -1;
     }
 
-    EVP_DigestInit(&ctx, EVP_sha1());
-    EVP_DigestUpdate(&ctx, sig_data, sig_datalen);
-    EVP_DigestFinal(&ctx, digest, &digestlen);
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+    pctx = EVP_MD_CTX_new();
+#else
+    pctx = &ctx;
+#endif /* prior to OpenSSL-1.1.0 */
+
+    EVP_DigestInit(pctx, EVP_sha1());
+    EVP_DigestUpdate(pctx, sig_data, sig_datalen);
+    EVP_DigestFinal(pctx, digest, &digestlen);
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+    EVP_MD_CTX_free(pctx);
+#endif /* OpenSSL-1.1.0 and later */
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+# if OPENSSL_VERSION_NUMBER >= 0x10100006L
+    DSA_SIG_set0(dsa_sig, sig_r, sig_s);
+# else
+    /* XXX What to do here? */
+# endif /* prior to OpenSSL-1.1.0-pre6 */
+#else
+    dsa_sig->r = sig_r;
+    dsa_sig->s = sig_s;
+#endif /* prior to OpenSSL-1.1.0 */
 
     ok = DSA_do_verify(digest, digestlen, dsa_sig, dsa);
     if (ok == 1) {
@@ -2801,6 +3001,7 @@ int sftp_keys_verify_signed_data(pool *p, const char *pubkey_algo,
              strncmp(sig_type, "ecdsa-sha2-nistp521", 20) == 0) {
     EC_KEY *ec;
     ECDSA_SIG *ecdsa_sig;
+    BIGNUM *sig_r, *sig_s;
     const EVP_MD *md = NULL;
     int ok;
 
@@ -2822,8 +3023,15 @@ int sftp_keys_verify_signed_data(pool *p, const char *pubkey_algo,
     sig = (unsigned char *) sftp_msg_read_data(p, &signature, &signaturelen,
       sig_len);
 
-    ecdsa_sig->r = sftp_msg_read_mpint(p, &sig, &sig_len);
-    if (ecdsa_sig->r == NULL) {
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+    ECDSA_SIG_get0(&sig_r, &sig_s, ecdsa_sig);
+#else
+    sig_r = ecdsa_sig->r;
+    sig_s = ecdsa_sig->s;
+#endif /* prior to OpenSSL-1.1.0 */
+
+    sig_r = sftp_msg_read_mpint(p, &sig, &sig_len);
+    if (sig_r == NULL) {
       (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
         "error reading 'r' ECDSA signature component: %s",
         sftp_crypto_get_errors());
@@ -2831,8 +3039,8 @@ int sftp_keys_verify_signed_data(pool *p, const char *pubkey_algo,
       return -1;
     }
 
-    ecdsa_sig->s = sftp_msg_read_mpint(p, &sig, &sig_len);
-    if (ecdsa_sig->s == NULL) {
+    sig_s = sftp_msg_read_mpint(p, &sig, &sig_len);
+    if (sig_s == NULL) {
       (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
         "error reading 's' ECDSA signature component: %s",
         sftp_crypto_get_errors());
@@ -2854,12 +3062,33 @@ int sftp_keys_verify_signed_data(pool *p, const char *pubkey_algo,
       md = EVP_sha512();
     }
 
-    EVP_DigestInit(&ctx, md);
-    EVP_DigestUpdate(&ctx, sig_data, sig_datalen);
-    EVP_DigestFinal(&ctx, digest, &digestlen);
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+    pctx = EVP_MD_CTX_new();
+#else
+    pctx = &ctx;
+#endif /* prior to OpenSSL-1.1.0 */
+
+    EVP_DigestInit(pctx, md);
+    EVP_DigestUpdate(pctx, sig_data, sig_datalen);
+    EVP_DigestFinal(pctx, digest, &digestlen);
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+    EVP_MD_CTX_free(pctx);
+#endif /* OpenSSL-1.1.0 and later */
 
     ec = EVP_PKEY_get1_EC_KEY(pkey);
 
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+# if OPENSSL_VERSION_NUMBER >= 0x10100006L
+    ECDSA_SIG_set0(ecdsa_sig, sig_r, sig_s);
+# else
+    /* XXX What to do here? */
+# endif /* prior to OpenSSL-1.1.0-pre6 */
+#else
+    ecdsa_sig->r = sig_r;
+    ecdsa_sig->s = sig_s;
+#endif /* prior to OpenSSL-1.1.0 */
+
     ok = ECDSA_do_verify(digest, digestlen, ecdsa_sig, ec);
     if (ok == 1) {
       res = 0;
diff --git a/contrib/mod_sftp/mac.c b/contrib/mod_sftp/mac.c
index 8660b93..852a790 100644
--- a/contrib/mod_sftp/mac.c
+++ b/contrib/mod_sftp/mac.c
@@ -1,6 +1,6 @@
 /*
  * ProFTPD - mod_sftp MACs
- * Copyright (c) 2008-2015 TJ Saunders
+ * Copyright (c) 2008-2016 TJ Saunders
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -66,14 +66,14 @@ static struct sftp_mac read_macs[] = {
   { NULL, 0, NULL, NULL, 0 },
   { NULL, 0, NULL, NULL, 0 }
 };
-static HMAC_CTX hmac_read_ctxs[2];
+static HMAC_CTX *hmac_read_ctxs[2];
 static struct umac_ctx *umac_read_ctxs[2];
 
 static struct sftp_mac write_macs[] = {
   { NULL, 0, NULL, NULL, 0 },
   { NULL, 0, NULL, NULL, 0 }
 };
-static HMAC_CTX hmac_write_ctxs[2];
+static HMAC_CTX *hmac_write_ctxs[2];
 static struct umac_ctx *umac_write_ctxs[2];
 
 static size_t mac_blockszs[2] = { 0, 0 };
@@ -103,12 +103,14 @@ static unsigned int get_next_write_index(void) {
 static void switch_read_mac(void) {
   /* First we can clear the read MAC, kept from rekeying. */
   if (read_macs[read_mac_idx].key) {
-    clear_mac(&(read_macs[read_mac_idx]));
-#if OPENSSL_VERSION_NUMBER > 0x000907000L
-    HMAC_CTX_cleanup(&(hmac_read_ctxs[read_mac_idx]));
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+    HMAC_CTX_reset(hmac_read_ctxs[read_mac_idx]);
+#elif OPENSSL_VERSION_NUMBER > 0x000907000L
+    HMAC_CTX_cleanup(hmac_read_ctxs[read_mac_idx]);
 #else
-    HMAC_cleanup(&(hmac_read_ctxs[read_mac_idx]));
+    HMAC_cleanup(hmac_read_ctxs[read_mac_idx]);
 #endif
+
     umac_reset(umac_read_ctxs[read_mac_idx]);
 
     mac_blockszs[read_mac_idx] = 0; 
@@ -127,11 +129,14 @@ static void switch_write_mac(void) {
   /* First we can clear the write MAC, kept from rekeying. */
   if (write_macs[write_mac_idx].key) {
     clear_mac(&(write_macs[write_mac_idx]));
-#if OPENSSL_VERSION_NUMBER > 0x000907000L
-    HMAC_CTX_cleanup(&(hmac_write_ctxs[write_mac_idx]));
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+    HMAC_CTX_reset(hmac_write_ctxs[write_mac_idx]);
+#elif OPENSSL_VERSION_NUMBER > 0x000907000L
+    HMAC_CTX_cleanup(hmac_write_ctxs[write_mac_idx]);
 #else
-    HMAC_cleanup(&(hmac_write_ctxs[write_mac_idx]));
+    HMAC_cleanup(hmac_write_ctxs[write_mac_idx]);
 #endif
+
     umac_reset(umac_write_ctxs[write_mac_idx]);
 
     /* Now we can switch the index. */
@@ -159,12 +164,15 @@ static void clear_mac(struct sftp_mac *mac) {
 
 static int init_mac(pool *p, struct sftp_mac *mac, HMAC_CTX *hmac_ctx,
     struct umac_ctx *umac_ctx) {
-#if OPENSSL_VERSION_NUMBER > 0x000907000L
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+  HMAC_CTX_reset(hmac_ctx);
+#elif OPENSSL_VERSION_NUMBER > 0x000907000L
   HMAC_CTX_init(hmac_ctx);
 #else
   /* Reset the HMAC context. */
   HMAC_Init(hmac_ctx, NULL, 0, NULL);
 #endif
+
   umac_reset(umac_ctx);
 
   if (mac->algo_type == SFTP_MAC_ALGO_TYPE_HMAC) {
@@ -363,7 +371,10 @@ static int get_mac(struct ssh2_packet *pkt, struct sftp_mac *mac,
 static int set_mac_key(struct sftp_mac *mac, const EVP_MD *hash,
     const unsigned char *k, uint32_t klen, const char *h, uint32_t hlen,
     char *letter, const unsigned char *id, uint32_t id_len) {
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
   EVP_MD_CTX ctx;
+#endif /* prior to OpenSSL-1.1.0 */
+  EVP_MD_CTX *pctx;
   unsigned char *key = NULL;
   size_t key_sz;
   uint32_t key_len = 0;
@@ -383,77 +394,101 @@ static int set_mac_key(struct sftp_mac *mac, const EVP_MD *hash,
     _exit(1);
   }
 
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+  pctx = &ctx;
+#else
+  pctx = EVP_MD_CTX_new();
+#endif /* prior to OpenSSL-1.1.0 */
+
   /* In OpenSSL 0.9.6, many of the EVP_Digest* functions returned void, not
    * int.  Without these ugly OpenSSL version preprocessor checks, the
    * compiler will error out with "void value not ignored as it ought to be".
    */
 
 #if OPENSSL_VERSION_NUMBER >= 0x000907000L
-  if (EVP_DigestInit(&ctx, hash) != 1) {
+  if (EVP_DigestInit(pctx, hash) != 1) {
     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
       "error initializing message digest: %s", sftp_crypto_get_errors());
     free(key);
+# if OPENSSL_VERSION_NUMBER >= 0x10100000L
+    EVP_MD_CTX_free(pctx);
+# endif /* OpenSSL-1.1.0 and later */
     return -1;
   }
 #else
-  EVP_DigestInit(&ctx, hash);
+  EVP_DigestInit(pctx, hash);
 #endif
 
 #if OPENSSL_VERSION_NUMBER >= 0x000907000L
-  if (EVP_DigestUpdate(&ctx, k, klen) != 1) {
+  if (EVP_DigestUpdate(pctx, k, klen) != 1) {
     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
       "error updating message digest with K: %s", sftp_crypto_get_errors());
     free(key);
+# if OPENSSL_VERSION_NUMBER >= 0x10100000L
+    EVP_MD_CTX_free(pctx);
+# endif /* OpenSSL-1.1.0 and later */
     return -1;
   }
 #else
-  EVP_DigestUpdate(&ctx, k, klen);
+  EVP_DigestUpdate(pctx, k, klen);
 #endif
 
 #if OPENSSL_VERSION_NUMBER >= 0x000907000L
-  if (EVP_DigestUpdate(&ctx, h, hlen) != 1) {
+  if (EVP_DigestUpdate(pctx, h, hlen) != 1) {
     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
       "error updating message digest with H: %s", sftp_crypto_get_errors());
     free(key);
+# if OPENSSL_VERSION_NUMBER >= 0x10100000L
+    EVP_MD_CTX_free(pctx);
+# endif /* OpenSSL-1.1.0 and later */
     return -1;
   }
 #else
-  EVP_DigestUpdate(&ctx, h, hlen);
+  EVP_DigestUpdate(pctx, h, hlen);
 #endif
 
 #if OPENSSL_VERSION_NUMBER >= 0x000907000L
-  if (EVP_DigestUpdate(&ctx, letter, sizeof(char)) != 1) {
+  if (EVP_DigestUpdate(pctx, letter, sizeof(char)) != 1) {
     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
       "error updating message digest with '%c': %s", *letter,
       sftp_crypto_get_errors());
     free(key);
+# if OPENSSL_VERSION_NUMBER >= 0x10100000L
+    EVP_MD_CTX_free(pctx);
+# endif /* OpenSSL-1.1.0 and later */
     return -1;
   }
 #else
-  EVP_DigestUpdate(&ctx, letter, sizeof(char));
+  EVP_DigestUpdate(pctx, letter, sizeof(char));
 #endif
 
 #if OPENSSL_VERSION_NUMBER >= 0x000907000L
-  if (EVP_DigestUpdate(&ctx, (char *) id, id_len) != 1) {
+  if (EVP_DigestUpdate(pctx, (char *) id, id_len) != 1) {
     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
       "error updating message digest with ID: %s", sftp_crypto_get_errors());
     free(key);
+# if OPENSSL_VERSION_NUMBER >= 0x10100000L
+    EVP_MD_CTX_free(pctx);
+# endif /* OpenSSL-1.1.0 and later */
     return -1;
   }
 #else
-  EVP_DigestUpdate(&ctx, (char *) id, id_len);
+  EVP_DigestUpdate(pctx, (char *) id, id_len);
 #endif
 
 #if OPENSSL_VERSION_NUMBER >= 0x000907000L
-  if (EVP_DigestFinal(&ctx, key, &key_len) != 1) {
+  if (EVP_DigestFinal(pctx, key, &key_len) != 1) {
     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
       "error finalizing message digest: %s", sftp_crypto_get_errors());
     pr_memscrub(key, key_sz);
     free(key);
+# if OPENSSL_VERSION_NUMBER >= 0x10100000L
+    EVP_MD_CTX_free(pctx);
+# endif /* OpenSSL-1.1.0 and later */
     return -1;
   }
 #else
-  EVP_DigestFinal(&ctx, key, &key_len);
+  EVP_DigestFinal(pctx, key, &key_len);
 #endif
 
   /* If we need more, keep hashing, as per RFC, until we have enough
@@ -466,64 +501,79 @@ static int set_mac_key(struct sftp_mac *mac, const EVP_MD *hash,
     pr_signals_handle();
 
 #if OPENSSL_VERSION_NUMBER >= 0x000907000L
-    if (EVP_DigestInit(&ctx, hash) != 1) {
+    if (EVP_DigestInit(pctx, hash) != 1) {
       (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
         "error initializing message digest: %s", sftp_crypto_get_errors());
       pr_memscrub(key, key_sz);
       free(key);
+# if OPENSSL_VERSION_NUMBER >= 0x10100000L
+      EVP_MD_CTX_free(pctx);
+# endif /* OpenSSL-1.1.0 and later */
       return -1;
     }
 #else
-    EVP_DigestInit(&ctx, hash);
+    EVP_DigestInit(pctx, hash);
 #endif
 
 #if OPENSSL_VERSION_NUMBER >= 0x000907000L
-    if (EVP_DigestUpdate(&ctx, k, klen) != 1) {
+    if (EVP_DigestUpdate(pctx, k, klen) != 1) {
       (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
         "error updating message digest with K: %s", sftp_crypto_get_errors());
       pr_memscrub(key, key_sz);
       free(key);
+# if OPENSSL_VERSION_NUMBER >= 0x10100000L
+      EVP_MD_CTX_free(pctx);
+# endif /* OpenSSL-1.1.0 and later */
       return -1;
     }
 #else
-    EVP_DigestUpdate(&ctx, k, klen);
+    EVP_DigestUpdate(pctx, k, klen);
 #endif
 
 #if OPENSSL_VERSION_NUMBER >= 0x000907000L
-    if (EVP_DigestUpdate(&ctx, h, hlen) != 1) {
+    if (EVP_DigestUpdate(pctx, h, hlen) != 1) {
       (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
         "error updating message digest with H: %s", sftp_crypto_get_errors());
       pr_memscrub(key, key_sz);
       free(key);
+# if OPENSSL_VERSION_NUMBER >= 0x10100000L
+      EVP_MD_CTX_free(pctx);
+# endif /* OpenSSL-1.1.0 and later */
       return -1;
     }
 #else
-    EVP_DigestUpdate(&ctx, h, hlen);
+    EVP_DigestUpdate(pctx, h, hlen);
 #endif
 
 #if OPENSSL_VERSION_NUMBER >= 0x000907000L
-    if (EVP_DigestUpdate(&ctx, key, len) != 1) {
+    if (EVP_DigestUpdate(pctx, key, len) != 1) {
       (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
         "error updating message digest with data: %s",
         sftp_crypto_get_errors());
       pr_memscrub(key, key_sz);
       free(key);
+# if OPENSSL_VERSION_NUMBER >= 0x10100000L
+      EVP_MD_CTX_free(pctx);
+# endif /* OpenSSL-1.1.0 and later */
       return -1;
     }
 #else
-    EVP_DigestUpdate(&ctx, key, len);
+    EVP_DigestUpdate(pctx, key, len);
 #endif
 
 #if OPENSSL_VERSION_NUMBER >= 0x000907000L
-    if (EVP_DigestFinal(&ctx, key + len, &len) != 1) {
+    if (EVP_DigestFinal(pctx, key + len, &len) != 1) {
       (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
         "error finalizing message digest: %s", sftp_crypto_get_errors());
       pr_memscrub(key, key_sz);
       free(key);
+# if OPENSSL_VERSION_NUMBER >= 0x10100000L
+      EVP_MD_CTX_free(pctx);
+# endif /* OpenSSL-1.1.0 and later */
       return -1;
     }
 #else
-    EVP_DigestFinal(&ctx, key + len, &len);
+    EVP_DigestFinal(pctx, key + len, &len);
 #endif
 
     key_len += len;
@@ -532,6 +582,10 @@ static int set_mac_key(struct sftp_mac *mac, const EVP_MD *hash,
   mac->key = key;
   mac->keysz = key_sz;
 
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+  EVP_MD_CTX_free(pctx);
+#endif /* OpenSSL-1.1.0 and later */
+
   if (mac->algo_type == SFTP_MAC_ALGO_TYPE_HMAC) {
     mac->key_len = EVP_MD_size(mac->digest);
 
@@ -604,7 +658,7 @@ int sftp_mac_set_read_key(pool *p, const EVP_MD *hash, const BIGNUM *k,
   switch_read_mac();
 
   mac = &(read_macs[read_mac_idx]);
-  hmac_ctx = &(hmac_read_ctxs[read_mac_idx]);
+  hmac_ctx = hmac_read_ctxs[read_mac_idx];
   umac_ctx = umac_read_ctxs[read_mac_idx];
 
   bufsz = buflen = SFTP_MAC_BUFSZ;
@@ -642,7 +696,7 @@ int sftp_mac_read_data(struct ssh2_packet *pkt) {
   int res;
 
   mac = &(read_macs[read_mac_idx]);
-  hmac_ctx = &(hmac_read_ctxs[read_mac_idx]);
+  hmac_ctx = hmac_read_ctxs[read_mac_idx];
   umac_ctx = umac_read_ctxs[read_mac_idx];
 
   if (mac->key == NULL) {
@@ -707,7 +761,7 @@ int sftp_mac_set_write_key(pool *p, const EVP_MD *hash, const BIGNUM *k,
   switch_write_mac();
 
   mac = &(write_macs[write_mac_idx]);
-  hmac_ctx = &(hmac_write_ctxs[write_mac_idx]);
+  hmac_ctx = hmac_write_ctxs[write_mac_idx];
   umac_ctx = umac_write_ctxs[write_mac_idx];
 
   bufsz = buflen = SFTP_MAC_BUFSZ;
@@ -737,7 +791,7 @@ int sftp_mac_write_data(struct ssh2_packet *pkt) {
   int res;
 
   mac = &(write_macs[write_mac_idx]);
-  hmac_ctx = &(hmac_write_ctxs[write_mac_idx]);
+  hmac_ctx = hmac_write_ctxs[write_mac_idx];
   umac_ctx = umac_write_ctxs[write_mac_idx];
 
   if (mac->key == NULL) {
@@ -755,18 +809,37 @@ int sftp_mac_write_data(struct ssh2_packet *pkt) {
   return 0;
 }
 
-int sftp_mac_init(void) {
-
-  umac_read_ctxs[0] = umac_alloc();
-  umac_read_ctxs[1] = umac_alloc();
-
-  umac_write_ctxs[0] = umac_alloc();
-  umac_write_ctxs[1] = umac_alloc();
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+/* In older versions of OpenSSL, there was not a way to dynamically allocate
+ * an HMAC_CTX object.  Thus we have these static objects for those
+ * older versions.
+ */
+static HMAC_CTX read_ctx1, read_ctx2;
+static HMAC_CTX write_ctx1, write_ctx2;
+#endif /* prior to OpenSSL-1.1.0 */
 
+int sftp_mac_init(void) {
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+  hmac_read_ctxs[0] = &read_ctx1;
+  hmac_read_ctxs[1] = &read_ctx2;
+  hmac_write_ctxs[0] = &write_ctx1;
+  hmac_write_ctxs[1] = &write_ctx2;
+#else
+  hmac_read_ctxs[0] = HMAC_CTX_new();
+  hmac_read_ctxs[1] = HMAC_CTX_new();
+  hmac_write_ctxs[0] = HMAC_CTX_new();
+  hmac_write_ctxs[1] = HMAC_CTX_new();
+#endif /* OpenSSL-1.1.0 and later */
   return 0;
 }
 
 int sftp_mac_free(void) {
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+  HMAC_CTX_free(hmac_read_ctxs[0]);
+  HMAC_CTX_free(hmac_read_ctxs[1]);
+  HMAC_CTX_free(hmac_write_ctxs[0]);
+  HMAC_CTX_free(hmac_write_ctxs[1]);
+#endif /* OpenSSL-1.1.0 and later */
 
   umac_delete(umac_read_ctxs[0]);
   umac_read_ctxs[0] = NULL;
diff --git a/contrib/mod_sftp/mod_sftp.c b/contrib/mod_sftp/mod_sftp.c
index 95cbd9d..eecf501 100644
--- a/contrib/mod_sftp/mod_sftp.c
+++ b/contrib/mod_sftp/mod_sftp.c
@@ -1,6 +1,6 @@
 /*
  * ProFTPD - mod_sftp
- * Copyright (c) 2008-2015 TJ Saunders
+ * Copyright (c) 2008-2016 TJ Saunders
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -31,6 +31,7 @@
 #include "packet.h"
 #include "interop.h"
 #include "crypto.h"
+#include "cipher.h"
 #include "mac.h"
 #include "keys.h"
 #include "keystore.h"
@@ -1451,6 +1452,7 @@ static void sftp_mod_unload_ev(const void *event_data, void *user_data) {
     sftp_interop_free();
     sftp_keystore_free();
     sftp_keys_free();
+    sftp_cipher_free();
     sftp_mac_free();
     pr_response_block(FALSE);
     sftp_utf8_free();
@@ -1504,6 +1506,7 @@ static void sftp_shutdown_ev(const void *event_data, void *user_data) {
   sftp_interop_free();
   sftp_keystore_free();
   sftp_keys_free();
+  sftp_cipher_free();
   sftp_mac_free();
   sftp_utf8_free();
 
@@ -1610,6 +1613,7 @@ static int sftp_init(void) {
   pr_log_debug(DEBUG2, MOD_SFTP_VERSION ": using " OPENSSL_VERSION_TEXT);
 
   sftp_keystore_init();
+  sftp_cipher_init();
   sftp_mac_init();
 
   pr_event_register(&sftp_module, "mod_ban.ban-class", sftp_ban_class_ev, NULL);
diff --git a/contrib/mod_sftp/msg.c b/contrib/mod_sftp/msg.c
index 7fdd8de..e00d24a 100644
--- a/contrib/mod_sftp/msg.c
+++ b/contrib/mod_sftp/msg.c
@@ -32,7 +32,6 @@
 # include <execinfo.h>
 #endif
 
-
 #ifdef PR_USE_OPENSSL_ECC
 /* Max GFp field length = 528 bits.  SEC1 uncompressed encoding uses 2
  * bitstring points.  SEC1 specifies a 1 byte point type header.
@@ -454,13 +453,15 @@ uint32_t sftp_msg_write_mpint(unsigned char **buf, uint32_t *buflen,
     return sftp_msg_write_int(buf, buflen, 0);
   }
 
-  if (mpint->neg) {
+#if OPENSSL_VERSION_NUMBER >= 0x0090801fL
+  if (BN_is_negative(mpint)) {
     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
       "message format error: unable to write mpint (negative numbers not "
       "supported)");
     log_stacktrace();
     SFTP_DISCONNECT_CONN(SFTP_SSH2_DISCONNECT_BY_APPLICATION, NULL);
   }
+#endif /* OpenSSL-0.9.8a or later */
 
   datalen = BN_num_bytes(mpint) + 1;
 
diff --git a/contrib/mod_sql.c b/contrib/mod_sql.c
index 605dbfd..1fd2170 100644
--- a/contrib/mod_sql.c
+++ b/contrib/mod_sql.c
@@ -2,7 +2,7 @@
  * ProFTPD: mod_sql -- SQL frontend
  * Copyright (c) 1998-1999 Johnie Ingram.
  * Copyright (c) 2001 Andrew Houghton.
- * Copyright (c) 2004-2014 TJ Saunders
+ * Copyright (c) 2004-2016 TJ Saunders
  *  
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -22,8 +22,6 @@
  * holders give permission to link this program with OpenSSL, and distribute
  * the resulting executable, without including the source code for OpenSSL in
  * the source distribution.
- *
- * $Id: mod_sql.c,v 1.247 2014-02-15 08:31:25 castaglia Exp $
  */
 
 #include "conf.h"
@@ -751,8 +749,7 @@ static modret_t *sql_auth_openssl(cmd_rec *cmd, const char *plaintext,
    * the form "{digest}hash".
    */
 
-  EVP_MD_CTX md_ctxt;
-  EVP_ENCODE_CTX base64_ctxt;
+  EVP_MD_CTX *md_ctx;
   const EVP_MD *md;
 
   /* According to RATS, the output buffer (buf) for EVP_EncodeBlock() needs to
@@ -793,12 +790,13 @@ static modret_t *sql_auth_openssl(cmd_rec *cmd, const char *plaintext,
     return PR_ERROR_INT(cmd, PR_AUTH_BADPWD);
   }
 
-  EVP_DigestInit(&md_ctxt, md);
-  EVP_DigestUpdate(&md_ctxt, plaintext, strlen(plaintext));
-  EVP_DigestFinal(&md_ctxt, mdval, &mdlen);
+  md_ctx = EVP_MD_CTX_create();
+  EVP_DigestInit(md_ctx, md);
+  EVP_DigestUpdate(md_ctx, plaintext, strlen(plaintext));
+  EVP_DigestFinal(md_ctx, mdval, &mdlen);
+  EVP_MD_CTX_destroy(md_ctx);
 
   memset(buf, '\0', sizeof(buf));
-  EVP_EncodeInit(&base64_ctxt);
   EVP_EncodeBlock(buf, mdval, (int) mdlen);
 
   if (strcmp((char *) buf, hashvalue) == 0) {
diff --git a/contrib/mod_sql_passwd.c b/contrib/mod_sql_passwd.c
index d6afd65..097341e 100644
--- a/contrib/mod_sql_passwd.c
+++ b/contrib/mod_sql_passwd.c
@@ -1,6 +1,6 @@
 /*
  * ProFTPD: mod_sql_passwd -- Various SQL password handlers
- * Copyright (c) 2009-2014 TJ Saunders
+ * Copyright (c) 2009-2016 TJ Saunders
  *  
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -20,8 +20,6 @@
  * give permission to link this program with OpenSSL, and distribute the
  * resulting executable, without including the source code for OpenSSL in
  * the source distribution.
- *
- * $Id: mod_sql_passwd.c,v 1.22 2014-05-05 16:15:02 castaglia Exp $
  */
 
 #include "conf.h"
@@ -199,7 +197,6 @@ static int get_pbkdf2_config(char *algo, const EVP_MD **md,
 }
 
 static char *sql_passwd_encode(pool *p, unsigned char *data, size_t data_len) {
-  EVP_ENCODE_CTX base64_ctxt;
   char *buf;
 
   /* According to RATS, the output buffer for EVP_EncodeBlock() needs to be
@@ -211,7 +208,6 @@ static char *sql_passwd_encode(pool *p, unsigned char *data, size_t data_len) {
 
   switch (sql_passwd_encoding) {
     case SQL_PASSWD_USE_BASE64:
-      EVP_EncodeInit(&base64_ctxt);
       EVP_EncodeBlock((unsigned char *) buf, data, (int) data_len);
       break;
 
@@ -254,7 +250,7 @@ static unsigned char *sql_passwd_hash(pool *p, const EVP_MD *md,
     unsigned char *suffix, size_t suffix_len,
     unsigned int *hash_len) {
 
-  EVP_MD_CTX md_ctx;
+  EVP_MD_CTX *md_ctx;
   unsigned char *hash;
 
   hash = palloc(p, EVP_MAX_MD_SIZE);
@@ -264,69 +260,76 @@ static unsigned char *sql_passwd_hash(pool *p, const EVP_MD *md,
    * compiler will error out with "void value not ignored as it ought to be".
    */
 
+  md_ctx = EVP_MD_CTX_create();
 #if OPENSSL_VERSION_NUMBER >= 0x000907000L
-  if (EVP_DigestInit(&md_ctx, md) != 1) {
+  if (EVP_DigestInit(md_ctx, md) != 1) {
     sql_log(DEBUG_WARN, MOD_SQL_PASSWD_VERSION
       ": error initializing '%s' digest: %s", OBJ_nid2ln(EVP_MD_type(md)),
       get_crypto_errors());
+    EVP_MD_CTX_destroy(md_ctx);
     errno = EPERM;
     return NULL;
   }
 #else
-  EVP_DigestInit(&md_ctx, md);
+  EVP_DigestInit(md_ctx, md);
 #endif
 
   if (prefix != NULL) {
 #if OPENSSL_VERSION_NUMBER >= 0x000907000L
-    if (EVP_DigestUpdate(&md_ctx, prefix, prefix_len) != 1) {
+    if (EVP_DigestUpdate(md_ctx, prefix, prefix_len) != 1) {
       sql_log(DEBUG_WARN, MOD_SQL_PASSWD_VERSION
         ": error updating '%s' digest: %s", OBJ_nid2ln(EVP_MD_type(md)),
         get_crypto_errors());
+      EVP_MD_CTX_destroy(md_ctx);
       errno = EPERM;
       return NULL;
     }
 #else
-    EVP_DigestUpdate(&md_ctx, prefix, prefix_len);
+    EVP_DigestUpdate(md_ctx, prefix, prefix_len);
 #endif
   }
 
 #if OPENSSL_VERSION_NUMBER >= 0x000907000L
-  if (EVP_DigestUpdate(&md_ctx, data, data_len) != 1) {
+  if (EVP_DigestUpdate(md_ctx, data, data_len) != 1) {
     sql_log(DEBUG_WARN, MOD_SQL_PASSWD_VERSION
       ": error updating '%s' digest: %s", OBJ_nid2ln(EVP_MD_type(md)),
       get_crypto_errors());
+    EVP_MD_CTX_destroy(md_ctx);
     errno = EPERM;
     return NULL;
   }
 #else
-  EVP_DigestUpdate(&md_ctx, data, data_len);
+  EVP_DigestUpdate(md_ctx, data, data_len);
 #endif
 
   if (suffix != NULL) {
 #if OPENSSL_VERSION_NUMBER >= 0x000907000L
-    if (EVP_DigestUpdate(&md_ctx, suffix, suffix_len) != 1) {
+    if (EVP_DigestUpdate(md_ctx, suffix, suffix_len) != 1) {
       sql_log(DEBUG_WARN, MOD_SQL_PASSWD_VERSION
         ": error updating '%s' digest: %s", OBJ_nid2ln(EVP_MD_type(md)),
         get_crypto_errors());
+      EVP_MD_CTX_destroy(md_ctx);
       errno = EPERM;
       return NULL;
     }
 #else
-    EVP_DigestUpdate(&md_ctx, suffix, suffix_len);
+    EVP_DigestUpdate(md_ctx, suffix, suffix_len);
 #endif
   }
 
 #if OPENSSL_VERSION_NUMBER >= 0x000907000L
-  if (EVP_DigestFinal(&md_ctx, hash, hash_len) != 1) {
+  if (EVP_DigestFinal(md_ctx, hash, hash_len) != 1) {
     sql_log(DEBUG_WARN, MOD_SQL_PASSWD_VERSION
       ": error finishing '%s' digest: %s", OBJ_nid2ln(EVP_MD_type(md)),
       get_crypto_errors());
+    EVP_MD_CTX_destroy(md_ctx);
     errno = EPERM;
     return NULL;
   }
 #else
-  EVP_DigestFinal(&md_ctx, hash, hash_len);
+  EVP_DigestFinal(md_ctx, hash, hash_len);
 #endif
+  EVP_MD_CTX_destroy(md_ctx);
 
   return hash;
 }
diff --git a/contrib/mod_tls.c b/contrib/mod_tls.c
index 68e8699..3ea53da 100644
--- a/contrib/mod_tls.c
+++ b/contrib/mod_tls.c
@@ -47,8 +47,10 @@
 */
 
 #include <openssl/err.h>
+#include <openssl/conf.h>
 #include <openssl/crypto.h>
 #include <openssl/evp.h>
+#include <openssl/ssl3.h>
 #include <openssl/x509v3.h>
 #include <openssl/pkcs12.h>
 #include <openssl/rand.h>
@@ -84,6 +86,57 @@ extern xaset_t *server_list;
  * Last updated on 2013-01-13.
  */
 
+static const char *trace_channel = "tls";
+
+static DH *get_dh(BIGNUM *p, BIGNUM *g) {
+  DH *dh;
+
+  dh = DH_new();
+  if (dh == NULL) {
+    return NULL;
+  }
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+  if (DH_set0_pqg(dh, p, NULL, g) != 1) {
+    pr_trace_msg(trace_channel, 3, "error setting DH p/q parameters: %s",
+      ERR_error_string(ERR_get_error(), NULL));
+    DH_free(dh);
+    return NULL;
+  }
+#else
+  dh->p = p;
+  dh->g = g;
+#endif /* OpenSSL 1.1.x and later */
+
+  return dh;
+}
+
+static X509 *read_cert(FILE *fh, SSL_CTX *ssl_ctx) {
+  X509 *cert;
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+  cert = PEM_read_X509(fh, NULL, SSL_CTX_get_default_passwd_cb(ssl_ctx),
+    SSL_CTX_get_default_passwd_cb_userdata(ssl_ctx));
+#else
+  cert = PEM_read_X509(fh, NULL, ssl_ctx->default_passwd_callback,
+    ssl_ctx->default_passwd_callback_userdata);
+#endif /* OpenSSL-1.1.x and later */
+
+  return cert;
+}
+
+static int get_pkey_type(EVP_PKEY *pkey) {
+  int pkey_type;
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+  pkey_type = EVP_PKEY_id(pkey);
+#else
+  pkey_type = EVP_PKEY_type(pkey->type);
+#endif /* OpenSSL 1.1.x and later */
+
+  return pkey_type;
+}
+
 /*
 -----BEGIN DH PARAMETERS-----
 MEYCQQC6VcB8+WFeFz/HQnk/vXreozxdppNBY4gN8rdzitjTDppPBswzU4ZL/hBS
@@ -105,22 +158,16 @@ static unsigned char dh512_g[] = {
 };
 
 static DH *get_dh512(void) {
-  DH *dh;
-
-  dh = DH_new();
-  if (dh == NULL)
-    return NULL;
-
-  dh->p = BN_bin2bn(dh512_p, sizeof(dh512_p), NULL);
-  dh->g = BN_bin2bn(dh512_g, sizeof(dh512_g), NULL);
+  BIGNUM *p, *g;
 
-  if (dh->p == NULL ||
-      dh->g == NULL) {
-    DH_free(dh);
+  p = BN_bin2bn(dh512_p, sizeof(dh512_p), NULL);
+  g = BN_bin2bn(dh512_g, sizeof(dh512_g), NULL);
+  if (p == NULL ||
+      g == NULL) {
     return NULL;
   }
 
-  return dh;
+  return get_dh(p, g);
 }
 
 /*
@@ -147,22 +194,16 @@ static unsigned char dh768_g[] = {
 };
 
 static DH *get_dh768(void) {
-  DH *dh;
+  BIGNUM *p, *g;
 
-  dh = DH_new();
-  if (dh == NULL)
-    return NULL;
-
-  dh->p = BN_bin2bn(dh768_p, sizeof(dh768_p), NULL);
-  dh->g = BN_bin2bn(dh768_g, sizeof(dh768_g), NULL);
-
-  if (dh->p == NULL ||
-      dh->g == NULL) {
-    DH_free(dh);
+  p = BN_bin2bn(dh768_p, sizeof(dh768_p), NULL);
+  g = BN_bin2bn(dh768_g, sizeof(dh768_g), NULL);
+  if (p == NULL ||
+      g == NULL) {
     return NULL;
   }
 
-  return dh;
+  return get_dh(p, g);
 }
 
 /*
@@ -192,22 +233,16 @@ static unsigned char dh1024_g[] = {
 };
 
 static DH *get_dh1024(void) {
-  DH *dh;
+  BIGNUM *p, *g;
 
-  dh = DH_new();
-  if (dh == NULL)
-    return NULL;
-
-  dh->p = BN_bin2bn(dh1024_p, sizeof(dh1024_p), NULL);
-  dh->g = BN_bin2bn(dh1024_g, sizeof(dh1024_g), NULL);
-
-  if (dh->p == NULL ||
-      dh->g == NULL) {
-    DH_free(dh);
+  p = BN_bin2bn(dh1024_p, sizeof(dh1024_p), NULL);
+  g = BN_bin2bn(dh1024_g, sizeof(dh1024_g), NULL);
+  if (p == NULL ||
+      g == NULL) {
     return NULL;
   }
 
-  return(dh);
+  return get_dh(p, g);
 }
 
 /*
@@ -244,22 +279,16 @@ static unsigned char dh1536_g[] = {
 };
 
 static DH *get_dh1536(void) {
-  DH *dh;
-
-  dh = DH_new();
-  if (dh == NULL)
-    return NULL;
+  BIGNUM *p, *g;
 
-  dh->p = BN_bin2bn(dh1536_p, sizeof(dh1536_p), NULL);
-  dh->g = BN_bin2bn(dh1536_g, sizeof(dh1536_g), NULL);
-
-  if (dh->p == NULL ||
-      dh->g == NULL) {
-    DH_free(dh);
+  p = BN_bin2bn(dh1536_p, sizeof(dh1536_p), NULL);
+  g = BN_bin2bn(dh1536_g, sizeof(dh1536_g), NULL);
+  if (p == NULL ||
+      g == NULL) {
     return NULL;
   }
 
-  return dh;
+  return get_dh(p, g);
 }
 
 /*
@@ -303,22 +332,16 @@ static unsigned char dh2048_g[] = {
 };
 
 static DH *get_dh2048(void) {
-  DH *dh;
+  BIGNUM *p, *g;
 
-  dh = DH_new();
-  if (dh == NULL)
-    return NULL;
-
-  dh->p = BN_bin2bn(dh2048_p, sizeof(dh2048_p), NULL);
-  dh->g = BN_bin2bn(dh2048_g, sizeof(dh2048_g), NULL);
-
-  if (dh->p == NULL ||
-      dh->g == NULL) {
-    DH_free(dh);
+  p = BN_bin2bn(dh2048_p, sizeof(dh2048_p), NULL);
+  g = BN_bin2bn(dh2048_g, sizeof(dh2048_g), NULL);
+  if (p == NULL ||
+      g == NULL) {
     return NULL;
   }
 
-  return dh;
+  return get_dh(p, g);
 }
 
 /* ASN1_BIT_STRING_cmp was renamed in 0.9.5 */
@@ -549,8 +572,8 @@ static int tls_sess_cache_remove(void);
 static int tls_sess_cache_status(pr_ctrls_t *, int);
 #endif /* PR_USE_CTRLS */
 static int tls_sess_cache_add_sess_cb(SSL *, SSL_SESSION *);
-static SSL_SESSION *tls_sess_cache_get_sess_cb(SSL *, unsigned char *, int,
-  int *);
+static SSL_SESSION *tls_sess_cache_get_sess_cb(SSL *, const unsigned char *,
+  int, int *);
 static void tls_sess_cache_delete_sess_cb(SSL_CTX *, SSL_SESSION *);
 
 #ifdef PR_USE_CTRLS
@@ -561,8 +584,6 @@ static ctrls_acttab_t tls_acttab[];
 static int tls_ctrl_need_init_handshake = TRUE;
 static int tls_data_need_init_handshake = TRUE;
 
-static const char *trace_channel = "tls";
-
 static void tls_diags_cb(const SSL *ssl, int where, int ret) {
   const char *str = "(unknown)";
   int w;
@@ -581,8 +602,29 @@ static void tls_diags_cb(const SSL *ssl, int where, int ret) {
     int ssl_state;
 
     ssl_state = SSL_get_state(ssl);
-    if (ssl_state == SSL_ST_OK) {
-      str = "ok";
+    switch (ssl_state) {
+#ifdef SSL_ST_BEFORE
+      case SSL_ST_BEFORE:
+        str = "before";
+        break;
+#endif
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+      case TLS_ST_OK:
+#else
+      case SSL_ST_OK:
+#endif /* OpenSSL-1.1.x and later */
+        str = "ok";
+        break;
+
+#ifdef SSL_ST_RENEGOTIATE
+      case SSL_ST_RENEGOTIATE:
+        str = "renegotiating";
+        break;
+#endif
+
+      default:
+        break;
     }
   }
 
@@ -591,8 +633,12 @@ static void tls_diags_cb(const SSL *ssl, int where, int ret) {
 
     ssl_state = SSL_get_state(ssl);
 
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+    if (ssl_state == TLS_ST_SR_CLNT_HELLO) {
+#else
     if (ssl_state == SSL3_ST_SR_CLNT_HELLO_A ||
         ssl_state == SSL23_ST_SR_CLNT_HELLO_A) {
+#endif /* OpenSSL-1.1.x and later */
 
       /* If we have already completed our initial handshake, then this might
        * a session renegotiation.
@@ -628,7 +674,8 @@ static void tls_diags_cb(const SSL *ssl, int where, int ret) {
         }
       }
 
-#if OPENSSL_VERSION_NUMBER >= 0x009080cfL
+#if OPENSSL_VERSION_NUMBER >= 0x009080cfL && \
+    OPENSSL_VERSION_NUMBER < 0x10100000L
     } else if (ssl_state & SSL_ST_RENEGOTIATE) {
       if ((ssl == ctrl_ssl && !tls_ctrl_need_init_handshake) ||
           (ssl != ctrl_ssl && !tls_data_need_init_handshake)) {
@@ -670,6 +717,11 @@ static void tls_diags_cb(const SSL *ssl, int where, int ret) {
       tls_log("[info] %s: %s", str, SSL_state_string_long(ssl));
     }
 
+  } else if (where & SSL_CB_HANDSHAKE_START) {
+    if (tls_opts & TLS_OPT_ENABLE_DIAGS) {
+      tls_log("[info] %s: %s", str, SSL_state_string_long(ssl));
+    }
+
   } else if (where & SSL_CB_HANDSHAKE_DONE) {
     if (ssl == ctrl_ssl) {
       if (tls_ctrl_need_init_handshake == FALSE) {
@@ -781,7 +833,18 @@ static void tls_msg_cb(int io_flag, int version, int content_type,
 #endif
 
     default:
+#ifdef SSL3_RT_HEADER
+      /* OpenSSL calls this callback for SSL records received; filter those
+       * from true "unknowns".
+       */
+      if (version == 0 &&
+          (content_type != SSL3_RT_HEADER ||
+           buflen != SSL3_RT_HEADER_LENGTH)) {
+        tls_log("[msg] unknown/unsupported version: %d", version);
+      }
+#else
       tls_log("[msg] unknown/unsupported version: %d", version);
+#endif
       break;
   }
 
@@ -1084,12 +1147,15 @@ static int tls_cert_match_dns_san(pool *p, X509 *cert, const char *dns_name) {
 
   sans = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
   if (sans != NULL) {
-    register unsigned int i;
+    register int i;
     int nsans = sk_GENERAL_NAME_num(sans);
 
     for (i = 0; i < nsans; i++) {
-      GENERAL_NAME *alt_name = sk_GENERAL_NAME_value(sans, i);
+      GENERAL_NAME *alt_name;
 
+      pr_signals_handle();
+
+      alt_name = sk_GENERAL_NAME_value(sans, i);
       if (alt_name->type == GEN_DNS) {
         char *dns_san;
         size_t dns_sanlen;
@@ -1146,12 +1212,15 @@ static int tls_cert_match_ip_san(pool *p, X509 *cert, const char *ipstr) {
 
   sans = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
   if (sans != NULL) {
-    register unsigned int i;
+    register int i;
     int nsans = sk_GENERAL_NAME_num(sans);
 
     for (i = 0; i < nsans; i++) {
-      GENERAL_NAME *alt_name = sk_GENERAL_NAME_value(sans, i);
+      GENERAL_NAME *alt_name;
+
+      pr_signals_handle();
 
+      alt_name = sk_GENERAL_NAME_value(sans, i);
       if (alt_name->type == GEN_IPADD) {
         unsigned char *san_data = NULL;
         int have_ipstr = FALSE, san_datalen;
@@ -2436,8 +2505,8 @@ static DH *tls_dh_cb(SSL *ssl, int is_export, int keylen) {
    */
   pkey = SSL_get_privatekey(ssl);
   if (pkey != NULL) {
-    if (EVP_PKEY_type(pkey->type) == EVP_PKEY_RSA ||
-        EVP_PKEY_type(pkey->type) == EVP_PKEY_DSA) {
+    if (get_pkey_type(pkey) == EVP_PKEY_RSA ||
+        get_pkey_type(pkey) == EVP_PKEY_DSA) {
       pkeylen = EVP_PKEY_bits(pkey);
 
       if (pkeylen < TLS_DH_MIN_LEN) {
@@ -2863,7 +2932,7 @@ static int tls_init_ctx(void) {
   }
 
   SSL_CTX_set_tmp_dh_callback(ssl_ctx, tls_dh_cb);
-#ifdef PR_USE_OPENSSL_ECC
+#if defined(PR_USE_OPENSSL_ECC) && OPENSSL_VERSION_NUMBER < 0x10100000L
   SSL_CTX_set_tmp_ecdh_callback(ssl_ctx, tls_ecdh_cb);
 #endif /* PR_USE_OPENSSL_ECC */
 
@@ -3147,8 +3216,7 @@ static int tls_init_server(void) {
       return -1;
     }
 
-    cert = PEM_read_X509(fh, NULL, ssl_ctx->default_passwd_callback,
-      ssl_ctx->default_passwd_callback_userdata);
+    cert = read_cert(fh, ssl_ctx);
     if (cert == NULL) {
       PRIVS_RELINQUISH
       tls_log("error reading TLSRSACertificateFile '%s': %s", tls_rsa_cert_file,
@@ -3220,8 +3288,7 @@ static int tls_init_server(void) {
       return -1;
     }
 
-    cert = PEM_read_X509(fh, NULL, ssl_ctx->default_passwd_callback,
-      ssl_ctx->default_passwd_callback_userdata);
+    cert = read_cert(fh, ssl_ctx);
     if (cert == NULL) {
       PRIVS_RELINQUISH
       tls_log("error reading TLSDSACertificateFile '%s': %s", tls_dsa_cert_file,
@@ -3293,8 +3360,7 @@ static int tls_init_server(void) {
       return -1;
     }
 
-    cert = PEM_read_X509(fh, NULL, ssl_ctx->default_passwd_callback,
-      ssl_ctx->default_passwd_callback_userdata);
+    cert = read_cert(fh, ssl_ctx);
     if (cert == NULL) {
       PRIVS_RELINQUISH
       tls_log("error reading TLSECCertificateFile '%s': %s", tls_ec_cert_file,
@@ -3430,7 +3496,7 @@ static int tls_init_server(void) {
 
     if (pkey &&
         tls_pkey) {
-      switch (EVP_PKEY_type(pkey->type)) {
+      switch (get_pkey_type(pkey)) {
         case EVP_PKEY_RSA:
           tls_pkey->flags |= TLS_PKEY_USE_RSA;
           tls_pkey->flags &= ~(TLS_PKEY_USE_DSA|TLS_PKEY_USE_EC);
@@ -3491,7 +3557,7 @@ static int tls_init_server(void) {
      * pointer around until after the handling of a cert chain file.
      */
     if (pkey != NULL) {
-      switch (EVP_PKEY_type(pkey->type)) {
+      switch (get_pkey_type(pkey)) {
         case EVP_PKEY_RSA:
           server_rsa_cert = cert;
           break;
@@ -4763,9 +4829,23 @@ static int tls_dotlogin_allow(const char *user) {
   }
 
   while ((file_cert = PEM_read_X509(fp, NULL, NULL, NULL))) {
+    const ASN1_BIT_STRING *client_sig = NULL, *file_sig = NULL;
+
     pr_signals_handle();
 
-    if (!M_ASN1_BIT_STRING_cmp(client_cert->signature, file_cert->signature)) {
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+    X509_get0_signature(&client_sig, NULL, client_cert);
+    X509_get0_signature(&file_sig, NULL, file_cert);
+#else
+    client_sig = client_cert->signature;
+    file_sig = file_cert->signature;
+#endif /* OpenSSL-1.1.x and later */
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+    if (!ASN1_STRING_cmp(client_sig, file_sig)) {
+#else
+    if (!M_ASN1_BIT_STRING_cmp(client_sig, file_sig)) {
+#endif /* OpenSSL-1.1.x and later */
       allow_user = TRUE;
     }
 
@@ -5233,87 +5313,98 @@ static void tls_setup_cert_ext_environ(const char *env_prefix, X509 *cert) {
 
 static void tls_setup_cert_dn_environ(const char *env_prefix, X509_NAME *name) {
   register unsigned int i = 0;
+  int nentries;
   char *k, *v;
 
-  for (i = 0; i < sk_X509_NAME_ENTRY_num(name->entries); i++) {
-    X509_NAME_ENTRY *entry = sk_X509_NAME_ENTRY_value(name->entries, i);
-    int nid = OBJ_obj2nid(entry->object);
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+  nentries = X509_NAME_entry_count(name);
+#else
+  nentries = sk_X509_NAME_ENTRY_num(name->entries);
+#endif /* OpenSSL-1.1.x and later */
+
+  for (i = 0; i < nentries; i++) {
+    X509_NAME_ENTRY *entry;
+    unsigned char *entry_data;
+    int nid, entry_len;
+
+    pr_signals_handle();
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+    entry = X509_NAME_get_entry(name, i);
+    nid = OBJ_obj2nid(X509_NAME_ENTRY_get_object(entry));
+    entry_data = ASN1_STRING_data(X509_NAME_ENTRY_get_data(entry));
+    entry_len = ASN1_STRING_length(X509_NAME_ENTRY_get_data(entry));
+#else
+    entry = sk_X509_NAME_ENTRY_value(name->entries, i);
+    nid = OBJ_obj2nid(entry->object);
+    entry_data = entry->value->data;
+    entry_len = entry->value->length;
+#endif /* OpenSSL-1.1.x and later */
 
     switch (nid) {
       case NID_countryName:
         k = pstrcat(session.pool, env_prefix, "C", NULL);
-        v = pstrndup(session.pool, (const char *) entry->value->data,
-          entry->value->length);
+        v = pstrndup(session.pool, (const char *) entry_data, entry_len);
         pr_env_set(session.pool, k, v);
         break;
 
       case NID_commonName:
         k = pstrcat(session.pool, env_prefix, "CN", NULL);
-        v = pstrndup(session.pool, (const char *) entry->value->data,
-          entry->value->length);
+        v = pstrndup(session.pool, (const char *) entry_data, entry_len);
         pr_env_set(session.pool, k, v);
         break;
 
       case NID_description:
         k = pstrcat(main_server->pool, env_prefix, "D", NULL);
-        v = pstrndup(main_server->pool, (const char *) entry->value->data,
-          entry->value->length);
+        v = pstrndup(session.pool, (const char *) entry_data, entry_len);
         pr_env_set(main_server->pool, k, v);
         break;
 
       case NID_givenName:
         k = pstrcat(main_server->pool, env_prefix, "G", NULL);
-        v = pstrndup(main_server->pool, (const char *) entry->value->data,
-          entry->value->length);
+        v = pstrndup(session.pool, (const char *) entry_data, entry_len);
         pr_env_set(main_server->pool, k, v);
         break;
 
       case NID_initials:
         k = pstrcat(main_server->pool, env_prefix, "I", NULL);
-        v = pstrndup(main_server->pool, (const char *) entry->value->data,
-          entry->value->length);
+        v = pstrndup(session.pool, (const char *) entry_data, entry_len);
         pr_env_set(main_server->pool, k, v);
         break;
 
       case NID_localityName:
         k = pstrcat(main_server->pool, env_prefix, "L", NULL);
-        v = pstrndup(main_server->pool, (const char *) entry->value->data,
-          entry->value->length);
+        v = pstrndup(session.pool, (const char *) entry_data, entry_len);
         pr_env_set(main_server->pool, k, v);
         break;
 
       case NID_organizationName:
         k = pstrcat(main_server->pool, env_prefix, "O", NULL);
-        v = pstrndup(main_server->pool, (const char *) entry->value->data,
-          entry->value->length);
+        v = pstrndup(session.pool, (const char *) entry_data, entry_len);
         pr_env_set(main_server->pool, k, v);
         break;
 
       case NID_organizationalUnitName:
         k = pstrcat(main_server->pool, env_prefix, "OU", NULL);
-        v = pstrndup(main_server->pool, (const char *) entry->value->data,
-          entry->value->length);
+        v = pstrndup(session.pool, (const char *) entry_data, entry_len);
         pr_env_set(main_server->pool, k, v);
         break;
 
       case NID_stateOrProvinceName:
         k = pstrcat(main_server->pool, env_prefix, "ST", NULL);
-        v = pstrndup(main_server->pool, (const char *) entry->value->data,
-          entry->value->length);
+        v = pstrndup(session.pool, (const char *) entry_data, entry_len);
         pr_env_set(main_server->pool, k, v);
         break;
 
       case NID_surname:
         k = pstrcat(main_server->pool, env_prefix, "S", NULL);
-        v = pstrndup(main_server->pool, (const char *) entry->value->data,
-          entry->value->length);
+        v = pstrndup(session.pool, (const char *) entry_data, entry_len);
         pr_env_set(main_server->pool, k, v);
         break;
 
       case NID_title:
         k = pstrcat(main_server->pool, env_prefix, "T", NULL);
-        v = pstrndup(main_server->pool, (const char *) entry->value->data,
-          entry->value->length);
+        v = pstrndup(session.pool, (const char *) entry_data, entry_len);
         pr_env_set(main_server->pool, k, v);
         break;
 
@@ -5323,15 +5414,13 @@ static void tls_setup_cert_dn_environ(const char *env_prefix, X509_NAME *name) {
       case NID_uniqueIdentifier:
 #endif
         k = pstrcat(main_server->pool, env_prefix, "UID", NULL);
-        v = pstrndup(main_server->pool, (const char *) entry->value->data,
-          entry->value->length);
+        v = pstrndup(session.pool, (const char *) entry_data, entry_len);
         pr_env_set(main_server->pool, k, v);
         break;
 
       case NID_pkcs9_emailAddress:
         k = pstrcat(main_server->pool, env_prefix, "Email", NULL);
-        v = pstrndup(main_server->pool, (const char *) entry->value->data,
-          entry->value->length);
+        v = pstrndup(session.pool, (const char *) entry_data, entry_len);
         pr_env_set(main_server->pool, k, v);
         break;
 
@@ -5349,6 +5438,8 @@ static void tls_setup_cert_environ(const char *env_prefix, X509 *cert) {
   if (tls_opts & TLS_OPT_STD_ENV_VARS) {
     char buf[80] = {'\0'};
     ASN1_INTEGER *serial = X509_get_serialNumber(cert);
+    X509_ALGOR *algo;
+    X509_PUBKEY *pubkey;
 
     memset(buf, '\0', sizeof(buf));
     snprintf(buf, sizeof(buf) - 1, "%lu", X509_get_version(cert) + 1);
@@ -5417,7 +5508,12 @@ static void tls_setup_cert_environ(const char *env_prefix, X509 *cert) {
     BIO_free(bio);
 
     bio = BIO_new(BIO_s_mem());
-    i2a_ASN1_OBJECT(bio, cert->cert_info->signature->algorithm);
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+    X509_get0_signature(NULL, &algo, cert);
+#else
+    algo = cert->cert_info->signature;
+#endif /* OpenSSL-1.1.x and later */
+    i2a_ASN1_OBJECT(bio, algo->algorithm);
     datalen = BIO_get_mem_data(bio, &data);
     data[datalen] = '\0';
 
@@ -5428,7 +5524,14 @@ static void tls_setup_cert_environ(const char *env_prefix, X509 *cert) {
     BIO_free(bio);
 
     bio = BIO_new(BIO_s_mem());
-    i2a_ASN1_OBJECT(bio, cert->cert_info->key->algor->algorithm);
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+    pubkey = X509_get_X509_PUBKEY(cert);
+    X509_PUBKEY_get0_param(NULL, NULL, NULL, &algo, pubkey);
+#else
+    pubkey = cert->cert_info->key;
+    algo = pubkey->algor;
+#endif /* OpenSSL-1.1.x and later */
+    i2a_ASN1_OBJECT(bio, algo->algorithm);
     datalen = BIO_get_mem_data(bio, &data);
     data[datalen] = '\0';
 
@@ -5477,12 +5580,20 @@ static void tls_setup_environ(SSL *ssl) {
     if (ssl_session) {
       char buf[SSL_MAX_SSL_SESSION_ID_LENGTH*2+1];
       register unsigned int i = 0;
+      const unsigned char *sess_data;
+      unsigned int sess_datalen;
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+      sess_data = SSL_SESSION_get_id(ssl_session, &sess_datalen);
+#else
+      sess_datalen = ssl_session->session_id_length;
+      sess_data = ssl_session->session_id;
+#endif /* OpenSSL-1.1.x and later */
 
       /* Have to obtain a stringified session ID the hard way. */
       memset(buf, '\0', sizeof(buf));
-      for (i = 0; i < ssl_session->session_id_length; i++) {
-        snprintf(&(buf[i*2]), sizeof(buf) - (i*2) - 1, "%02X",
-          ssl_session->session_id[i]);
+      for (i = 0; i < sess_datalen; i++) {
+        snprintf(&(buf[i*2]), sizeof(buf) - (i*2) - 1, "%02X", sess_data[i]);
       }
       buf[sizeof(buf)-1] = '\0';
 
@@ -5621,8 +5732,13 @@ static int tls_verify_cb(int ok, X509_STORE_CTX *ctx) {
 
   if (!ok) {
     X509 *cert = X509_STORE_CTX_get_current_cert(ctx);
-    int depth = X509_STORE_CTX_get_error_depth(ctx);
+    int ctx_error, depth = X509_STORE_CTX_get_error_depth(ctx);
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+    verify_err = X509_STORE_CTX_get_error(ctx);
+#else
     verify_err = ctx->error;
+#endif /* OpenSSL-1.1.x and later */
 
     tls_log("error: unable to verify certificate at depth %d", depth);
     tls_log("error: cert subject: %s", tls_x509_name_oneline(
@@ -5631,10 +5747,17 @@ static int tls_verify_cb(int ok, X509_STORE_CTX *ctx) {
       X509_get_issuer_name(cert)));
 
     /* Catch a too long certificate chain here. */
-    if (depth > tls_verify_depth)
+    if (depth > tls_verify_depth) {
       X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_CHAIN_TOO_LONG);
+    }
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+    ctx_error = X509_STORE_CTX_get_error(ctx);
+#else
+    ctx_error = ctx->error;
+#endif /* OpenSSL-1.1.x and later */
 
-    switch (ctx->error) {
+    switch (ctx_error) {
       case X509_V_ERR_CERT_CHAIN_TOO_LONG:
       case X509_V_ERR_CERT_HAS_EXPIRED:
       case X509_V_ERR_CERT_REVOKED:
@@ -5644,7 +5767,7 @@ static int tls_verify_cb(int ok, X509_STORE_CTX *ctx) {
       case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
       case X509_V_ERR_APPLICATION_VERIFICATION:
         tls_log("client certificate failed verification: %s",
-          X509_verify_cert_error_string(ctx->error));
+          X509_verify_cert_error_string(ctx_error));
         ok = 0;
         break;
 
@@ -5653,7 +5776,7 @@ static int tls_verify_cb(int ok, X509_STORE_CTX *ctx) {
         int count = X509_PURPOSE_get_count();
 
         tls_log("client certificate failed verification: %s",
-          X509_verify_cert_error_string(ctx->error));
+          X509_verify_cert_error_string(ctx_error));
 
         for (i = 0; i < count; i++) {
           X509_PURPOSE *purp = X509_PURPOSE_get0(i);
@@ -5666,7 +5789,7 @@ static int tls_verify_cb(int ok, X509_STORE_CTX *ctx) {
 
       default:
         tls_log("error verifying client certificate: [%d] %s",
-          ctx->error, X509_verify_cert_error_string(ctx->error));
+          ctx_error, X509_verify_cert_error_string(ctx_error));
         ok = 0;
         break;
     }
@@ -5686,11 +5809,10 @@ static int tls_verify_cb(int ok, X509_STORE_CTX *ctx) {
  * <rse@engelshall.com>.  Comments by Ralf.
  */
 static int tls_verify_crl(int ok, X509_STORE_CTX *ctx) {
-  X509_OBJECT obj;
   X509_NAME *subject = NULL, *issuer = NULL;
   X509 *xs = NULL;
-  X509_CRL *crl = NULL;
-  X509_STORE_CTX store_ctx;
+  STACK_OF(X509_CRL) *crls = NULL;
+  X509_STORE_CTX *store_ctx = NULL;
   int n, res;
   register int i = 0;
 
@@ -5749,128 +5871,149 @@ static int tls_verify_crl(int ok, X509_STORE_CTX *ctx) {
   /* Try to retrieve a CRL corresponding to the _subject_ of
    * the current certificate in order to verify its integrity.
    */
-  memset(&obj, 0, sizeof(obj));
+  store_ctx = X509_STORE_CTX_new();
 #if OPENSSL_VERSION_NUMBER > 0x000907000L
-  if (X509_STORE_CTX_init(&store_ctx, tls_crl_store, NULL, NULL) <= 0) {
+  if (X509_STORE_CTX_init(store_ctx, tls_crl_store, NULL, NULL) <= 0) {
     tls_log("error initializing CRL store context: %s", tls_get_errors());
+    X509_STORE_CTX_free(store_ctx);
     return ok;
   }
 #else
-  X509_STORE_CTX_init(&store_ctx, tls_crl_store, NULL, NULL);
+  X509_STORE_CTX_init(store_ctx, tls_crl_store, NULL, NULL);
 #endif
 
-  res = X509_STORE_get_by_subject(&store_ctx, X509_LU_CRL, subject, &obj);
-  crl = obj.data.crl;
-
-  if (res > 0 &&
-      crl != NULL) {
-    EVP_PKEY *pubkey;
-    char buf[512];
-    int len;
-    BIO *b = BIO_new(BIO_s_mem());
-
-    BIO_printf(b, "CA CRL: Issuer: ");
-    X509_NAME_print(b, issuer, 0);
-
-    BIO_printf(b, ", lastUpdate: ");
-    ASN1_UTCTIME_print(b, crl->crl->lastUpdate);
+  crls = X509_STORE_CTX_get1_crls(store_ctx, subject);
+  if (crls != NULL) {
+    for (i = 0; i < sk_X509_CRL_num(crls); i++) {
+      X509_CRL *crl = NULL;
+      EVP_PKEY *pubkey;
+      char buf[512];
+      int len;
+      BIO *b = BIO_new(BIO_s_mem());
+
+      BIO_printf(b, "CA CRL: Issuer: ");
+      X509_NAME_print(b, issuer, 0);
+
+      BIO_printf(b, ", lastUpdate: ");
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+      ASN1_UTCTIME_print(b, X509_CRL_get_lastUpdate(crl));
+#else
+      ASN1_UTCTIME_print(b, crl->crl->lastUpdate);
+#endif /* OpenSSL-1.1.x and later */
 
-    BIO_printf(b, ", nextUpdate: ");
-    ASN1_UTCTIME_print(b, crl->crl->nextUpdate);
+      BIO_printf(b, ", nextUpdate: ");
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+      ASN1_UTCTIME_print(b, X509_CRL_get_nextUpdate(crl));
+#else
+      ASN1_UTCTIME_print(b, crl->crl->nextUpdate);
+#endif /* OpenSSL-1.1.x and later */
 
-    len = BIO_read(b, buf, sizeof(buf) - 1);
-    if (len >= sizeof(buf)) {
-      len = sizeof(buf)-1;
-    }
-    buf[len] = '\0';
+      len = BIO_read(b, buf, sizeof(buf) - 1);
+      if (len >= sizeof(buf)) {
+        len = sizeof(buf)-1;
+      }
+      buf[len] = '\0';
 
-    BIO_free(b);
+      BIO_free(b);
+      tls_log("%s", buf);
 
-    tls_log("%s", buf);
+      pubkey = X509_get_pubkey(xs);
 
-    pubkey = X509_get_pubkey(xs);
+      /* Verify the signature on this CRL */
+      res = X509_CRL_verify(crl, pubkey);
+      if (pubkey) {
+        EVP_PKEY_free(pubkey);
+      }
 
-    /* Verify the signature on this CRL */
-    res = X509_CRL_verify(crl, pubkey);
+      if (res <= 0) {
+        tls_log("invalid signature on CRL: %s", tls_get_errors());
 
-    if (pubkey) {
-      EVP_PKEY_free(pubkey);
-    }
+        X509_STORE_CTX_set_error(ctx, X509_V_ERR_CRL_SIGNATURE_FAILURE);
+        sk_X509_CRL_free(crls);
+        X509_STORE_CTX_cleanup(store_ctx);
+        X509_STORE_CTX_free(store_ctx);
+        return FALSE;
+      }
 
-    if (res <= 0) {
-      tls_log("invalid signature on CRL: %s", tls_get_errors());
+      /* Check date of CRL to make sure it's not expired */
+      res = X509_cmp_current_time(X509_CRL_get_nextUpdate(crl));
+      if (res == 0) {
+        tls_log("CRL has invalid nextUpdate field: %s", tls_get_errors());
 
-      X509_STORE_CTX_set_error(ctx, X509_V_ERR_CRL_SIGNATURE_FAILURE);
-      X509_OBJECT_free_contents(&obj);
-      X509_STORE_CTX_cleanup(&store_ctx);
-      return FALSE;
-    }
+        X509_STORE_CTX_set_error(ctx,
+          X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD);
+        sk_X509_CRL_free(crls);
+        X509_STORE_CTX_cleanup(store_ctx);
+        X509_STORE_CTX_free(store_ctx);
+        return FALSE;
+      }
 
-    /* Check date of CRL to make sure it's not expired */
-    i = X509_cmp_current_time(X509_CRL_get_nextUpdate(crl));
-    if (i == 0) {
-      tls_log("CRL has invalid nextUpdate field: %s", tls_get_errors());
-      X509_STORE_CTX_set_error(ctx, X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD);
-      X509_OBJECT_free_contents(&obj);
-      X509_STORE_CTX_cleanup(&store_ctx);
-      return FALSE;
-    }
+      if (res < 0) {
+        /* XXX This is a bit draconian, rejecting all certificates if the CRL
+         * has expired.  See also Bug#3216, about automatically reloading
+         * the CRL file when it has expired.
+         */
+        tls_log("%s", "CRL is expired, revoking all certificates until an "
+          "updated CRL is obtained");
 
-    if (i < 0) {
-      /* XXX This is a bit draconian, rejecting all certificates if the CRL
-       * has expired.  See also Bug#3216, about automatically reloading
-       * the CRL file when it has expired.
-       */
-      tls_log("%s", "CRL is expired, revoking all certificates until an "
-        "updated CRL is obtained");
-      X509_STORE_CTX_set_error(ctx, X509_V_ERR_CRL_HAS_EXPIRED);
-      X509_OBJECT_free_contents(&obj);
-      X509_STORE_CTX_cleanup(&store_ctx);
-      return FALSE;
+        X509_STORE_CTX_set_error(ctx, X509_V_ERR_CRL_HAS_EXPIRED);
+        sk_X509_CRL_free(crls);
+        X509_STORE_CTX_cleanup(store_ctx);
+        X509_STORE_CTX_free(store_ctx);
+        return FALSE;
+      }
     }
 
-    X509_OBJECT_free_contents(&obj);
+    sk_X509_CRL_free(crls);
+    crls = NULL;
   }
 
   /* Try to retrieve a CRL corresponding to the _issuer_ of
    * the current certificate in order to check for revocation.
    */
-  memset(&obj, 0, sizeof(obj));
-
-  res = X509_STORE_get_by_subject(&store_ctx, X509_LU_CRL, issuer, &obj);
-  crl = obj.data.crl;
 
-  if (res > 0 &&
-      crl != NULL) {
+  crls = X509_STORE_CTX_get1_crls(store_ctx, issuer);
+  if (crls != NULL) {
+    for (i = 0; i < sk_X509_CRL_num(crls); i++) {
+      register int j;
+      X509_CRL *crl;
 
-    /* Check if the current certificate is revoked by this CRL */
-    n = sk_X509_REVOKED_num(X509_CRL_get_REVOKED(crl));
+      crl = sk_X509_CRL_value(crls, i);
 
-    for (i = 0; i < n; i++) {
-      X509_REVOKED *revoked;
-      ASN1_INTEGER *sn;
+      /* Check if the current certificate is revoked by this CRL */
+      n = sk_X509_REVOKED_num(X509_CRL_get_REVOKED(crl));
+      for (j = 0; j < n; j++) {
+        X509_REVOKED *revoked;
+        ASN1_INTEGER *sn;
 
-      revoked = sk_X509_REVOKED_value(X509_CRL_get_REVOKED(crl), i);
-      sn = revoked->serialNumber;
+        revoked = sk_X509_REVOKED_value(X509_CRL_get_REVOKED(crl), i);
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+        sn = X509_REVOKED_get0_serialNumber(revoked);
+#else
+        sn = revoked->serialNumber;
+#endif /* OpenSSL-1.1.x and later */
 
-      if (ASN1_INTEGER_cmp(sn, X509_get_serialNumber(xs)) == 0) {
-        long serial = ASN1_INTEGER_get(sn);
-        char *cp = tls_x509_name_oneline(issuer);
+        if (ASN1_INTEGER_cmp(sn, X509_get_serialNumber(xs)) == 0) {
+          long serial = ASN1_INTEGER_get(sn);
+          char *cp = tls_x509_name_oneline(issuer);
 
-        tls_log("certificate with serial number %ld (0x%lX) revoked per CRL "
-          "from issuer '%s'", serial, serial, cp ? cp : "(ERROR)");
+          tls_log("certificate with serial number %ld (0x%lX) revoked per CRL "
+            "from issuer '%s'", serial, serial, cp ? cp : "(ERROR)");
 
-        X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_REVOKED);
-        X509_OBJECT_free_contents(&obj);
-        X509_STORE_CTX_cleanup(&store_ctx);
-        return FALSE;
+          X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_REVOKED);
+          sk_X509_CRL_free(crls);
+          X509_STORE_CTX_cleanup(store_ctx);
+          X509_STORE_CTX_free(store_ctx);
+          return FALSE;
+        }
       }
     }
 
-    X509_OBJECT_free_contents(&obj);
+    sk_X509_CRL_free(crls);
   }
 
-  X509_STORE_CTX_cleanup(&store_ctx);
+  X509_STORE_CTX_cleanup(store_ctx);
+  X509_STORE_CTX_free(store_ctx);
   return ok;
 }
 
@@ -5879,6 +6022,7 @@ static int tls_verify_ocsp_url(X509_STORE_CTX *ctx, X509 *cert,
     const char *url) {
   BIO *conn;
   X509 *issuing_cert = NULL;
+  X509_STORE *store = NULL;
   X509_NAME *subj = NULL;
   const char *subj_name;
   char *host = NULL, *port = NULL, *uri = NULL;
@@ -6209,7 +6353,12 @@ static int tls_verify_ocsp_url(X509_STORE_CTX *ctx, X509 *cert,
     return FALSE;
   }
 
-  res = OCSP_basic_verify(basic_resp, NULL, ctx->ctx, 0);
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+  store = X509_STORE_CTX_get0_store(ctx);
+#else
+  store = ctx->ctx;
+#endif /* OpenSSL-1.1.x and later */
+  res = OCSP_basic_verify(basic_resp, NULL, store, 0);
   if (res != 1) {
     tls_log("error verifying basic response from OCSP responder at '%s': %s",
       url, tls_get_errors());
@@ -6912,7 +7061,7 @@ static int tls_sess_cache_add_sess_cb(SSL *ssl, SSL_SESSION *sess) {
 }
 
 static SSL_SESSION *tls_sess_cache_get_sess_cb(SSL *ssl,
-    unsigned char *sess_id, int sess_id_len, int *do_copy) {
+    const unsigned char *sess_id, int sess_id_len, int *do_copy) {
   SSL_SESSION *sess;
 
   /* Indicate to OpenSSL that the ref count should not be incremented
diff --git a/contrib/mod_tls.h b/contrib/mod_tls.h
index b8cb001..32078d1 100644
--- a/contrib/mod_tls.h
+++ b/contrib/mod_tls.h
@@ -80,7 +80,7 @@ typedef struct sess_cache_st {
   /* Add a new session entry to the cache.  The provided sess_id is effectively
    * the cache lookup key.
    */
-  int (*add)(struct sess_cache_st *cache, unsigned char *sess_id,
+  int (*add)(struct sess_cache_st *cache, const unsigned char *sess_id,
     unsigned int sess_id_len, time_t expires, SSL_SESSION *sess);
 
   /* Retrieve a session from the cache, using the provided sess_id key. */
diff --git a/contrib/mod_tls_shmcache.c b/contrib/mod_tls_shmcache.c
index b558349..e39ec64 100644
--- a/contrib/mod_tls_shmcache.c
+++ b/contrib/mod_tls_shmcache.c
@@ -2,7 +2,7 @@
  * ProFTPD: mod_tls_shmcache -- a module which provides a shared SSL session
  *                              cache using SysV shared memory
  *
- * Copyright (c) 2009-2013 TJ Saunders
+ * Copyright (c) 2009-2016 TJ Saunders
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -27,7 +27,6 @@
  * For more information contact TJ Saunders <tj@castaglia.org>.
  *
  *  --- DO NOT DELETE BELOW THIS LINE ----
- *  $Id: mod_tls_shmcache.c,v 1.15 2013-11-05 21:37:16 castaglia Exp $
  *  $Libraries: -lssl -lcrypto$
  */
 
@@ -1423,6 +1422,7 @@ static int shmcache_status(tls_sess_cache_t *cache,
         SSL_SESSION *sess;
         TLS_D2I_SSL_SESSION_CONST unsigned char *ptr;
         time_t ts;
+        int ssl_version;
 
         ptr = entry->sess_data;
         sess = d2i_SSL_SESSION(NULL, &ptr, entry->sess_datalen); 
@@ -1435,34 +1435,36 @@ static int shmcache_status(tls_sess_cache_t *cache,
 
         statusf(arg, "%s", "  -----BEGIN SSL SESSION PARAMETERS-----");
 
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
         /* XXX Directly accessing these fields cannot be a Good Thing. */
         if (sess->session_id_length > 0) {
-          register unsigned int j;
           char *sess_id_str;
 
-          sess_id_str = pcalloc(tmp_pool, (sess->session_id_length * 2) + 1);
-
-          for (j = 0; j < sess->session_id_length; j++) {
-            sprintf((char *) &(sess_id_str[j*2]), "%02X", sess->session_id[j]);
-          }
+          sess_id_str = pr_str_bin2hex(tmp_pool, sess->session_id,
+            sess->session_id_length, PR_STR_FL_HEX_USE_UC);
 
           statusf(arg, "    Session ID: %s", sess_id_str);
         }
 
         if (sess->sid_ctx_length > 0) {
-          register unsigned int j;
           char *sid_ctx_str;
 
-          sid_ctx_str = pcalloc(tmp_pool, (sess->sid_ctx_length * 2) + 1);
-
-          for (j = 0; j < sess->sid_ctx_length; j++) {
-            sprintf((char *) &(sid_ctx_str[j*2]), "%02X", sess->sid_ctx[j]);
-          }
+          sid_ctx_str = pr_str_bin2hex(tmp_pool, sess->sid_ctx,
+            sess->sid_ctx_length, PR_STR_FL_HEX_USE_UC);
 
           statusf(arg, "    Session ID Context: %s", sid_ctx_str);
         }
 
-        switch (sess->ssl_version) {
+        ssl_version = sess->ssl_version;
+#else
+# if OPENSSL_VERSION_NUMBER >= 0x10100006L
+        ssl_version = SSL_SESSION_get_protocol_version(sess);
+# else
+        ssl_version = 0;
+# endif /* prior to OpenSSL-1.1.0-pre5 */
+#endif /* prior to OpenSSL-1.1.x */
+
+        switch (ssl_version) {
           case SSL3_VERSION:
             statusf(arg, "    Protocol: %s", "SSLv3");
             break;
diff --git a/src/table.c b/src/table.c
index 1a6bb38..0695e86 100644
--- a/src/table.c
+++ b/src/table.c
@@ -1,6 +1,6 @@
 /*
  * ProFTPD - FTP server daemon
- * Copyright (c) 2004-2012 The ProFTPD Project team
+ * Copyright (c) 2004-2016 The ProFTPD Project team
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -22,9 +22,7 @@
  * OpenSSL in the source distribution.
  */
 
-/* Table API implementation
- * $Id: table.c,v 1.32 2012-02-24 01:37:27 castaglia Exp $
- */
+/* Table API implementation */
 
 #include "conf.h"
 
@@ -369,9 +367,7 @@ static unsigned int tab_get_seed(void) {
 #endif /* Not PR_USE_OPENSSL */
 
 #ifdef PR_USE_OPENSSL
-  if (RAND_bytes((unsigned char *) &seed, sizeof(seed)) != 1) {
-    RAND_pseudo_bytes((unsigned char *) &seed, sizeof(seed));
-  }
+  RAND_bytes((unsigned char *) &seed, sizeof(seed));
 #else
   /* Try reading from /dev/urandom, if present */
   fp = fopen("/dev/urandom", "rb");

From d56b61dd316011a9bd0158f34c730348d70fdf5c Mon Sep 17 00:00:00 2001
From: TJ Saunders <tj@castaglia.org>
Date: Thu, 17 Nov 2016 07:12:39 -0800
Subject: [PATCH 2/6] Typo.

---
 NEWS | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

#diff --git a/NEWS b/NEWS
#index 40ed935..b422a6a 100644
#--- a/NEWS
#+++ b/NEWS
#@@ -16,7 +16,7 @@
# - Bug 4255 - "AuthAliasOnly on" in server config breaks anonymous logins.
# - Bug 4272 - CapabilitiesEngine directive not honored for <IfUser>/<IfGroup>
#   sections.
#-- Bug 4275 - Support OpenSSL 1.1.x API..
#+- Bug 4275 - Support OpenSSL 1.1.x API.
# 
# 1.3.5b - Released 10-Mar-2016
# --------------------------------
#
From c2f6c7eaa8ad94866221bccf001e7270cd8f2212 Mon Sep 17 00:00:00 2001
From: TJ Saunders <tj@castaglia.org>
Date: Thu, 17 Nov 2016 07:30:18 -0800
Subject: [PATCH 3/6] Fix broken build.

---
 contrib/mod_sftp/fxp.c     | 2 +-
 contrib/mod_tls_shmcache.c | 7 +++++--
 2 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/contrib/mod_sftp/fxp.c b/contrib/mod_sftp/fxp.c
index 0d8478d..b189412 100644
--- a/contrib/mod_sftp/fxp.c
+++ b/contrib/mod_sftp/fxp.c
@@ -2616,7 +2616,7 @@ static struct fxp_handle *fxp_handle_create(pool *p) {
      */
     pr_signals_handle();
 
-    RAND_pseudo_bytes(data, data_len);
+    RAND_bytes(data, data_len);
 
     /* Encode the data as hex to create the handle ID. */
     for (i = 0; i < data_len; i++) {
diff --git a/contrib/mod_tls_shmcache.c b/contrib/mod_tls_shmcache.c
index e39ec64..bfcd6af 100644
--- a/contrib/mod_tls_shmcache.c
+++ b/contrib/mod_tls_shmcache.c
@@ -1438,10 +1438,13 @@ static int shmcache_status(tls_sess_cache_t *cache,
 #if OPENSSL_VERSION_NUMBER < 0x10100000L
         /* XXX Directly accessing these fields cannot be a Good Thing. */
         if (sess->session_id_length > 0) {
+          register unsigned int j;
           char *sess_id_str;
 
-          sess_id_str = pr_str_bin2hex(tmp_pool, sess->session_id,
-            sess->session_id_length, PR_STR_FL_HEX_USE_UC);
+          sess_id_str = pcalloc(tmp_pool, (sess->session_id_length * 2) + 1);
+          for (j = 0; j < sess->session_id_length; j++) {
+            sprintf((char *) &(sess_id_str[j*2]), "%02X", sess->session_id[j]);
+          }
 
           statusf(arg, "    Session ID: %s", sess_id_str);
         }

From 0e27c53177db6e1ce4196c772c119071678c77a7 Mon Sep 17 00:00:00 2001
From: TJ Saunders <tj@castaglia.org>
Date: Thu, 17 Nov 2016 07:34:56 -0800
Subject: [PATCH 4/6] Another version nit, backported from master.

---
 contrib/mod_tls.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/contrib/mod_tls.c b/contrib/mod_tls.c
index 3ea53da..797c125 100644
--- a/contrib/mod_tls.c
+++ b/contrib/mod_tls.c
@@ -5882,7 +5882,11 @@ static int tls_verify_crl(int ok, X509_STORE_CTX *ctx) {
   X509_STORE_CTX_init(store_ctx, tls_crl_store, NULL, NULL);
 #endif
 
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
   crls = X509_STORE_CTX_get1_crls(store_ctx, subject);
+#else
+  crls = X509_STORE_get1_crls(store_ctx, subject);
+#endif /* OpenSSL-1.1.x and later */
   if (crls != NULL) {
     for (i = 0; i < sk_X509_CRL_num(crls); i++) {
       X509_CRL *crl = NULL;
@@ -5972,7 +5976,11 @@ static int tls_verify_crl(int ok, X509_STORE_CTX *ctx) {
    * the current certificate in order to check for revocation.
    */
 
-  crls = X509_STORE_CTX_get1_crls(store_ctx, issuer);
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+  crls = X509_STORE_CTX_get1_crls(store_ctx, subject);
+#else
+  crls = X509_STORE_get1_crls(store_ctx, subject);
+#endif /* OpenSSL-1.1.x and later */
   if (crls != NULL) {
     for (i = 0; i < sk_X509_CRL_num(crls); i++) {
       register int j;

From 8a46bf2c32fda8ccfd50657b465b1adbc0b1b5e3 Mon Sep 17 00:00:00 2001
From: TJ Saunders <tj@castaglia.org>
Date: Thu, 17 Nov 2016 07:37:22 -0800
Subject: [PATCH 5/6] Remove another backported use of pr_str_bin2hex().

---
 contrib/mod_tls_shmcache.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/contrib/mod_tls_shmcache.c b/contrib/mod_tls_shmcache.c
index bfcd6af..ea31925 100644
--- a/contrib/mod_tls_shmcache.c
+++ b/contrib/mod_tls_shmcache.c
@@ -1450,10 +1450,13 @@ static int shmcache_status(tls_sess_cache_t *cache,
         }
 
         if (sess->sid_ctx_length > 0) {
+          register unsigned int j;
           char *sid_ctx_str;
 
-          sid_ctx_str = pr_str_bin2hex(tmp_pool, sess->sid_ctx,
-            sess->sid_ctx_length, PR_STR_FL_HEX_USE_UC);
+          sid_ctx_str = pcalloc(tmp_pool, (sess->sid_ctx_length * 2) + 1);
+          for (j = 0; j < sess->sid_ctx_length; j++) {
+            sprintf((char *) &(sid_ctx_str[j*2]), "%02X", sess->sid_ctx[j]);
+          }
 
           statusf(arg, "    Session ID Context: %s", sid_ctx_str);
         }

From 88e94044c3f92d29141c8ceaa0489a8d193eca85 Mon Sep 17 00:00:00 2001
From: TJ Saunders <tj@castaglia.org>
Date: Thu, 17 Nov 2016 07:49:51 -0800
Subject: [PATCH 6/6] Copy-pastos.

---
 contrib/mod_sftp/crypto.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/contrib/mod_sftp/crypto.c b/contrib/mod_sftp/crypto.c
index 1f5e5e3..cdb435c 100644
--- a/contrib/mod_sftp/crypto.c
+++ b/contrib/mod_sftp/crypto.c
@@ -810,9 +810,9 @@ static const EVP_MD *get_umac_digest(void) {
   umac_digest.pkey_type = NID_undef;
   umac_digest.md_size = 8;
   umac_digest.flags = 0UL;
-  umac_digest.update = update_umac64;
-  umac_digest.final = final_umac64;
-  umac_digest.cleanup = delete_umac64;
+  umac_digest.update = update_umac;
+  umac_digest.final = final_umac;
+  umac_digest.cleanup = delete_umac;
   umac_digest.block_size = 32;
 
   md = &umac_digest;
From 694b5b4a8172a2f8349eca62204b180099145187 Mon Sep 17 00:00:00 2001
From: TJ Saunders <tj@castaglia.org>
Date: Thu, 17 Nov 2016 18:02:38 -0800
Subject: [PATCH] Try avoid build errors with *really* old OpenSSL versions
 (i.e. pre-1.0.0).

---
 contrib/mod_tls.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/contrib/mod_tls.c b/contrib/mod_tls.c
index 797c125..75721e0 100644
--- a/contrib/mod_tls.c
+++ b/contrib/mod_tls.c
@@ -5884,8 +5884,11 @@ static int tls_verify_crl(int ok, X509_STORE_CTX *ctx) {
 
 #if OPENSSL_VERSION_NUMBER >= 0x10100000L
   crls = X509_STORE_CTX_get1_crls(store_ctx, subject);
-#else
+#elif OPENSSL_VERSION_NUMBER >= 0x10000000L
   crls = X509_STORE_get1_crls(store_ctx, subject);
+#else
+  /* Your OpenSSL is before 1.0.0.  You really need to upgrade. */
+  crls = NULL;
 #endif /* OpenSSL-1.1.x and later */
   if (crls != NULL) {
     for (i = 0; i < sk_X509_CRL_num(crls); i++) {
@@ -5978,8 +5981,11 @@ static int tls_verify_crl(int ok, X509_STORE_CTX *ctx) {
 
 #if OPENSSL_VERSION_NUMBER >= 0x10100000L
   crls = X509_STORE_CTX_get1_crls(store_ctx, subject);
-#else
+#elif OPENSSL_VERSION_NUMBER >= 0x10000000L
   crls = X509_STORE_get1_crls(store_ctx, subject);
+#else
+  /* Your OpenSSL is before 1.0.0.  You really need to upgrade. */
+  crls = NULL;
 #endif /* OpenSSL-1.1.x and later */
   if (crls != NULL) {
     for (i = 0; i < sk_X509_CRL_num(crls); i++) {