August 21, 2013

Fixing "Could not generate DH keypair" on RedditLater.com

RedditLater.com is a little app I made last April. It worked fine until sometime in July, when Reddit released an improvement to its SSL configuration on its api. Thereafter, attempts to get an access token using clj-http-lite began to fail with a javax.net.ssl.SSLException: Could not generate DH keypair exception.

Some investigation led me to a stackoverflow post (where else) which led me to this eventual workaround: hack up clj-http-lite to wrap the default SSLSocketFactory in a new class that would remove all the unsupported algorithms from the list of supported ones.

Here’s the class I added:

(ns clj-http.lite.NoDHSocketFactory
  (:import (javax.net.ssl SSLSocket SSLSocketFactory)
           (java.net Socket))
  (:gen-class
    :name clj-http.lite.NoDHSocketFactory
    :extends javax.net.ssl.SSLSocketFactory
    :init init
    :state state
    :constructors {[javax.net.ssl.SSLSocketFactory] []}))

(defn strip-dh-suites
  "Remove cipher suites containing 'DH'"
  [suites]
  (into-array String (filter #(not (or (re-find #"_DHE_" %)
                                       (re-find #"_DH_" %)
                                       (re-find #"_ECDH_" %)
                                       (re-find #"_ECDHE_" %))) suites)))

(defn -init
  [^SSLSocketFactory f]
  (let [state {:factory f
               :enabled-ciphers (strip-dh-suites (.getSupportedCipherSuites f))}]

    [[] (atom state)]))

(defn -createSocket [this & args]
  (doto
    (apply (partial (memfn createSocket) (:factory @(.state this))) args)
    (.setEnabledCipherSuites (:enabled-ciphers @(.state this)))))

(defn -getDefaultCipherSuites [this]
  (strip-dh-suites (.getDefaultCipherSuites (:factory @(.state this)))))

(defn -getSupportedCipherSuites [this]
  (strip-dh-suites (.getSupportedCipherSuites (:factory @(.state this)))))

I’ve submitted a pull request here, although I don’t expect such a hacky workaround to be accepted. I’ve also published my mangled version of clj-http-lite at clojars (as version 0.2.2-SNAPSHOT).

If you’re experiencing this problem (which is specific to the regular HttpsURLConnection, not to clj-http-lite), hopefully this helps you along.