#ifdef USE_SSL
  
 +               /*
 +                * Enable the libcrypto callbacks before checking if SSL needs
 +                * to be done.  This is done before sending the startup packet
 +                * as depending on the type of authentication done, like MD5
 +                * or SCRAM that use cryptohashes, the callbacks would be
 +                * required even without a SSL connection
 +                */
 +               if (pqsecure_initialize(conn, false, true) < 0)
 +                   goto error_return;
 +
                 /*
                  * If SSL is enabled and we haven't already got encryption of
                  * some sort running, request SSL instead of sending the
                      {
                         /* mark byte consumed */
                         conn->inStart = conn->inCursor;
 -                       /* Set up global SSL state if required */
 -                       if (pqsecure_initialize(conn) != 0)
 +
 +                       /*
 +                        * Set up global SSL state if required.  The crypto
 +                        * state has already been set if libpq took care of
 +                        * doing that, so there is no need to make that happen
 +                        * again.
 +                        */
 +                       if (pqsecure_initialize(conn, true, false) != 0)
                             goto error_return;
                     }
                     else if (SSLok == 'N')
          static bool ssl_lib_initialized = false;
  
  #ifdef ENABLE_THREAD_SAFETY
 -static long ssl_open_connections = 0;
 +static long crypto_open_connections = 0;
  
  #ifndef WIN32
  static pthread_mutex_t ssl_config_mutex = PTHREAD_MUTEX_INITIALIZER;
       * Disallow changing the flags while we have open connections, else we'd
      * get completely confused.
      */
 -   if (ssl_open_connections != 0)
 +   if (crypto_open_connections != 0)
         return;
  #endif
  
    * override it.
   */
  int
 -pgtls_init(PGconn *conn)
 +pgtls_init(PGconn *conn, bool do_ssl, bool do_crypto)
  {
  #ifdef ENABLE_THREAD_SAFETY
  #ifdef WIN32
              }
         }
  
 -       if (ssl_open_connections++ == 0)
 +       if (do_crypto && !conn->crypto_loaded)
         {
 -           /*
 -            * These are only required for threaded libcrypto applications,
 -            * but make sure we don't stomp on them if they're already set.
 -            */
 -           if (CRYPTO_get_id_callback() == NULL)
 -               CRYPTO_set_id_callback(pq_threadidcallback);
 -           if (CRYPTO_get_locking_callback() == NULL)
 -               CRYPTO_set_locking_callback(pq_lockingcallback);
 +           if (crypto_open_connections++ == 0)
 +           {
 +               /*
 +                * These are only required for threaded libcrypto
 +                * applications, but make sure we don't stomp on them if
 +                * they're already set.
 +                */
 +               if (CRYPTO_get_id_callback() == NULL)
 +                   CRYPTO_set_id_callback(pq_threadidcallback);
 +               if (CRYPTO_get_locking_callback() == NULL)
 +                   CRYPTO_set_locking_callback(pq_lockingcallback);
 +           }
 +
 +           conn->crypto_loaded = true;
         }
     }
  #endif                         /* HAVE_CRYPTO_LOCK */
  #endif                         /* ENABLE_THREAD_SAFETY */
  
 -   if (!ssl_lib_initialized)
 +   if (!ssl_lib_initialized && do_ssl)
     {
         if (pq_init_ssl_lib)
         {
      if (pthread_mutex_lock(&ssl_config_mutex))
         return;
  
 -   if (pq_init_crypto_lib && ssl_open_connections > 0)
 -       --ssl_open_connections;
 +   if (pq_init_crypto_lib && crypto_open_connections > 0)
 +       --crypto_open_connections;
  
 -   if (pq_init_crypto_lib && ssl_open_connections == 0)
 +   if (pq_init_crypto_lib && crypto_open_connections == 0)
     {
         /*
          * No connections left, unregister libcrypto callbacks, if no one
   {
     bool        destroy_needed = false;
  
 -   if (conn->ssl)
 +   if (conn->ssl_in_use)
     {
 -       /*
 -        * We can't destroy everything SSL-related here due to the possible
 -        * later calls to OpenSSL routines which may need our thread
 -        * callbacks, so set a flag here and check at the end.
 -        */
 -       destroy_needed = true;
 +       if (conn->ssl)
 +       {
 +           /*
 +            * We can't destroy everything SSL-related here due to the
 +            * possible later calls to OpenSSL routines which may need our
 +            * thread callbacks, so set a flag here and check at the end.
 +            */
  
 -       SSL_shutdown(conn->ssl);
 -       SSL_free(conn->ssl);
 -       conn->ssl = NULL;
 -       conn->ssl_in_use = false;
 -   }
 +           SSL_shutdown(conn->ssl);
 +           SSL_free(conn->ssl);
 +           conn->ssl = NULL;
 +           conn->ssl_in_use = false;
  
 -   if (conn->peer)
 -   {
 -       X509_free(conn->peer);
 -       conn->peer = NULL;
 -   }
 +           destroy_needed = true;
 +       }
 +
 +       if (conn->peer)
 +       {
 +           X509_free(conn->peer);
 +           conn->peer = NULL;
 +       }
  
  #ifdef USE_SSL_ENGINE
 -   if (conn->engine)
 +       if (conn->engine)
 +       {
 +           ENGINE_finish(conn->engine);
 +           ENGINE_free(conn->engine);
 +           conn->engine = NULL;
 +       }
 +#endif
 +   }
 +   else
     {
 -       ENGINE_finish(conn->engine);
 -       ENGINE_free(conn->engine);
 -       conn->engine = NULL;
 +       /*
 +        * In the non-SSL case, just remove the crypto callbacks if the
 +        * connection has then loaded.  This code path has no dependency
 +        * on any pending SSL calls.
 +        */
 +       if (conn->crypto_loaded)
 +           destroy_needed = true;
     }
 -#endif
  
     /*
 -    * This will remove our SSL locking hooks, if this is the last SSL
 -    * connection, which means we must wait to call it until after all SSL
 -    * calls have been made, otherwise we can end up with a race condition and
 -    * possible deadlocks.
 +    * This will remove our crypto locking hooks if this is the last
 +    * connection using libcrypto which means we must wait to call it until
 +    * after all the potential SSL calls have been made, otherwise we can end
 +    * up with a race condition and possible deadlocks.
      *
      * See comments above destroy_ssl_system().
      */
     if (destroy_needed)
 +   {
         destroy_ssl_system();
 +       conn->crypto_loaded = false;
 +   }
  }
  
  
             void       *engine;         /* dummy field to keep struct the same if
                                  * OpenSSL version changes */
  #endif
 +   bool        crypto_loaded;  /* Track if libcrypto locking callbacks have
 +                                * been done for this connection. This can be
 +                                * removed once support for OpenSSL 1.0.2 is
 +                                * removed as this locking is handled
 +                                * internally in OpenSSL >= 1.1.0. */
  #endif                         /* USE_OPENSSL */
  #endif                         /* USE_SSL */
  
   
  /* === in fe-secure.c === */
  
 -extern int pqsecure_initialize(PGconn *);
 +extern int pqsecure_initialize(PGconn *, bool, bool);
  extern PostgresPollingStatusType pqsecure_open_client(PGconn *);
  extern void pqsecure_close(PGconn *);
  extern ssize_t pqsecure_read(PGconn *, void *ptr, size_t len);
    * Initialize SSL library.
   *
   * The conn parameter is only used to be able to pass back an error
 - * message - no connection-local setup is made here.
 + * message - no connection-local setup is made here.  do_ssl controls
 + * if SSL is initialized, and do_crypto does the same for the crypto
 + * part.
   *
   * Returns 0 if OK, -1 on failure (adding a message to conn->errorMessage).
   */
 -extern int pgtls_init(PGconn *conn);
 +extern int pgtls_init(PGconn *conn, bool do_ssl, bool do_crypto);
  
  /*
   * Begin or continue negotiating a secure session.