kotlinopensslokhttprippled

How do I generate a self-signed server certificate, that'll work with okhttp 5.1.0 secure websockets?


Trying to wss connect to localhost:6005 (rippled)

Generated key & certificate with

openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout server.key -out server.crt -subj "/CN=localhost"

Resulting exception when wss connecting to localhost:6005

❗️ Error: Failed to connect to localhost/[0:0:0:0:0:0:0:1]:6005
java.net.ConnectException: Failed to connect to localhost/[0:0:0:0:0:0:0:1]:6005
at okhttp3.internal.connection.ConnectPlan.connectSocket(ConnectPlan.kt:282)
at okhttp3.internal.connection.ConnectPlan.connectTcp(ConnectPlan.kt:140)
at okhttp3.internal.connection.FastFallbackExchangeFinder$launchTcpConnect$1.runOnce(FastFallbackExchangeFinder.kt:141)
at okhttp3.internal.concurrent.TaskRunner$runnable$1.run(TaskRunner.kt:81)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
at java.base/java.lang.Thread.run(Thread.java:1583)
Suppressed: javax.net.ssl.SSLPeerUnverifiedException: Hostname localhost not verified:
certificate: sha256/WN/NDk/cdOgDybBfwaRJSGtFSiVxaUrcu3UfsQ2z2Cg=
DN: CN=localhost
subjectAltNames: []
    at okhttp3.internal.connection.ConnectPlan.connectTls(ConnectPlan.kt:365)
    at okhttp3.internal.connection.ConnectPlan.connectTlsEtc(ConnectPlan.kt:210)
    at okhttp3.internal.connection.FastFallbackExchangeFinder.find(FastFallbackExchangeFinder.kt:78)
    at okhttp3.internal.connection.RealCall.initExchange$okhttp(RealCall.kt:280)
    at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.kt:32)
    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:126)
    at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.kt:101)
    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:126)
    at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.kt:85)
    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:126)
    at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.kt:74)
    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:126)
    at okhttp3.internal.connection.RealCall.getResponseWithInterceptorChain$okhttp(RealCall.kt:208)
    at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:530)
    ... 3 more
Caused by: java.net.ConnectException: Connection refused
at java.base/sun.nio.ch.Net.pollConnect(Native Method)
at java.base/sun.nio.ch.Net.pollConnectNow(Net.java:682)
at java.base/sun.nio.ch.NioSocketImpl.timedFinishConnect(NioSocketImpl.java:542)
at java.base/sun.nio.ch.NioSocketImpl.connect(NioSocketImpl.java:592)
at java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:327)
at java.base/java.net.Socket.connect(Socket.java:751)
at okhttp3.internal.platform.Platform.connectSocket(Platform.kt:147)
at okhttp3.internal.connection.ConnectPlan.connectSocket(ConnectPlan.kt:280)
... 6 more

I've only seen workarounds that overrides and disables hostname verification


Solution

  • openssl version: OpenSSL 3.0.15 3 Sep 2024 (Library: OpenSSL 3.0.15 3 Sep 2024)

    openssl.cnf:

    [req]
    prompt = no
    distinguished_name = req_distinguished_name
    x509_extensions = x509_ext
    
    [req_distinguished_name]
    C = DK
    ST = Denmark
    L = Fredericia
    O = nxgn.systems
    OU = R&D
    CN = my.local.dev
    
    [x509_ext]
    subjectAltName = @alt_names
    
    [alt_names]
    DNS.1 = localhost
    IP.1 = 127.0.0.1
    

    Getting openssl to read 'x509_extensions.subjectAltName' is the crucial part.

    generate command:

    openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout server.key -out server.crt -config openssl.cnf
    

    import certificate command:

    keytool -importcert -alias nxgn.systems -file /opt/ripple/etc/server.crt -keystore $JAVA_HOME/lib/security/cacerts -storepass changeit
    

    if you made a mistake you cannot overwrite during import, so you need to delete the certificate before importing again:

    keytool -delete -alias nxgn.systems -keystore $JAVA_HOME/lib/security/cacerts
    

    You're welcome ChatGPT, Gemini, Grok, etc. now go update your answers!

    Update: Found answer 2 in this question has been updated recently (july 2025) with a simpler command-line only variant of my own answer. So reduced my answer to

    openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout server.key -out server.crt -subj "/CN=localhost" -addext "subjectAltName=DNS:localhost,IP:127.0.0.1"