Search code examples
rubysecurityopensslnet-httphsm

How to use a custom OpenSSL engine for Net::HTTP


I am trying to use a custom OpenSSL engine for crypto operations required for client certificate authentication.

Currently Net::HTTP lets us pass only the cert and key which will be used for the client authentication. We are moving all private keys to HSM ("Hardware Security Module") so instead of the default OpenSSL engine we want to plug-in a custom OpenSSL engine. The custom OpenSSL engine will perform private key signing operations using HSM.

Current with the default engine we have code something like:

http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = uri.scheme == 'https'
http.cert = OpenSSL::X509::Certificate.new(File.read("/tmp/cert.pem"))
http.key = OpenSSL::PKey::RSA.new(File.read('/tmp/key_pointer.pem'))
http.ssl_version = :TLSv1_2
http.open_timeout = open_timeout
http.read_timeout = read_timeout
request = Net::HTTP::Post.new(uri)
request.body = "body goes here"
response = http.request(request)

I tried searching for how to plug-in a custom OpenSSL engine for Net::HTTP but couldn't find anything. How can we use a custom engine for signing using a private key as part of the client certificate authentication?


Solution

  • I got a work around for this. Since Net::HTTP use OpenSSL for encryption during client certificate authentication. Instead of passing key, I used the key handle by custom engine and operations performed(signing) on that during client certificate authentication were relayed to HSM. Here is how sample code looks like:

    http = Net::HTTP.new(uri.host, uri.port)
    http.use_ssl = uri.scheme == 'https'
    http.cert = OpenSSL::X509::Certificate.new(File.read("/tmp/cert.pem"))
    OpenSSL::Engine.load
    http.key =  OpenSSL::Engine.by_id("EngineId").load_private_key("CKA_LABEL=rsa-private-client-cert-auth-test-9ik98jui98")
    http.ssl_version = :TLSv1_2
    http.open_timeout = open_timeout
    http.read_timeout = read_timeout
    request = Net::HTTP::Post.new(uri)
    request.body = "body goes here"
    response = http.request(request)