Quantcast
Channel: Active questions tagged https - Stack Overflow
Viewing all articles
Browse latest Browse all 1534

javax.net.ssl.SSLHandshakeException: (certificate_unknown) in Scala client via NGINX

$
0
0

Problem:

I have been back and forth for the last week or so trying to configure my Scala+AKKA client to be able to send message to a server running NGINX.

I keep getting the error:javax.net.ssl.SSLHandshakeException: (certificate_unknown)

Setup:

nginx config:

server {    listen 443 ssl default_server;    listen [::]:443 ssl default_server;    server_name localhost;    ssl_certificate /home/hydra/.localhost-ssl/localhost.crt;           //<- combined certificates (server_cert + rootCA)    ssl_certificate_key /home/hydra/.localhost-ssl/localhost-key.key;    ssl_trusted_certificate /home/hydra/.localhost-ssl/rootCA.crt;      //<- just the rootCA    index index.html index.htm;    root /home/hydra/ui/;    location / {        try_files $uri.html $uri/index.html        @public        @nextjs;        add_header Cache-Control "public, max-age=3600";    }    location @public {        add_header Cache-Control "public, max-age=3600";    }    location /ping {        proxy_pass http://localhost:8080;    }    location @nextjs {            proxy_pass http://localhost:3000;            proxy_http_version 1.1;            proxy_set_header Upgrade $http_upgrade;            proxy_set_header Connection 'upgrade';            proxy_set_header Host $host;            proxy_cache_bypass $http_upgrade;            proxy_set_header X-Real-IP $remote_addr;            proxy_set_header X-Forwarded-Proto https;            proxy_set_header X-Forwarded-For $remote_addr;            proxy_set_header X-Forwarded-Host $remote_addr;    }}

client request:

  private val sslContext: SSLContext = SSLManager.getClientSSLContext  private val connectionContext = ConnectionContext.httpsClient(sslContext)...    val request = HttpRequest(method = HttpMethods.GET, uri = s"https://${server.serverIP}/ping")    http.singleRequest(request, connectionContext).pipeTo(self)

createClientContext:

  def getClientSSLContext: SSLContext = {    val keyStore = KeyStore.getInstance("JKS")    keyStore.load(null, null) // Create an empty keystore    keyStore.setCertificateEntry("rootCA", loadRootCertificate())    // Set up a TrustManager that trusts the root CA certificate    val trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm)    trustManagerFactory.init(keyStore)    val trustManagers = trustManagerFactory.getTrustManagers    // Create an SSLContext with the custom TrustManager    val sslContext = SSLContext.getInstance("TLS")    sslContext.init(null, trustManagers, new SecureRandom())    sslContext  }

Writing rootCA to file:

    val rootCA = new StringBuilder()    rootCA.append("-----BEGIN CERTIFICATE-----\n")    rootCA.append(Base64.getEncoder.encodeToString(rootCACertificate.getEncoded))    rootCA.append("\n-----END CERTIFICATE-----")    writeFile(ROOT_CA_PATH, Seq(rootCA.toString))

How I create the signed server certificate:

def createCSR(keyPair: KeyPair, subject: String, keyAlgorithm: String): PKCS10CertificationRequest = {    val csrGen = new PKCS10CertificationRequestBuilder(new X500Name(subject), SubjectPublicKeyInfo.getInstance(keyPair.getPublic.getEncoded))    val signer = new JcaContentSignerBuilder("SHA256with" + keyAlgorithm).build(keyPair.getPrivate)    csrGen.build(signer)  }  // Sign the CSR with the root CA's private key to generate a certificate  def signCertificate(csr: PKCS10CertificationRequest, rootCACertificate: X509Certificate, rootCAPrivateKey: PrivateKey): X509Certificate = {    val notBefore = new Date()    val notAfter = new Date(notBefore.getTime + 36500L * 24 * 60 * 60 * 1000) // Valid for 1 year    val certGen = new X509v3CertificateBuilder(      new X500Name("CN=Hydra SSL Certificate"),      new BigInteger(128, new Random()),      notBefore,      notAfter,      csr.getSubject,      csr.getSubjectPublicKeyInfo    )    // Add SubjectAlternativeName (SAN) extension    val sanNames = Array[GeneralName](      new GeneralName(GeneralName.iPAddress, SERVER_IP)    )    val generalNames = new GeneralNames(sanNames)    certGen.addExtension(Extension.subjectAlternativeName, false, generalNames)    // Sign with root CA's private key    val signer = new JcaContentSignerBuilder("SHA256withRSA").build(rootCAPrivateKey)    val certificateHolder: X509CertificateHolder = certGen.build(signer)    // Convert to a JCE certificate    val converter = new JcaX509CertificateConverter().setProvider("BC")    converter.getCertificate(certificateHolder)  }...    // Step 1: Load Root CA certificate and private key    val rootCACertificate = loadRootCertificate()    val rootCAPrivateKey = loadRootPrivateKey()    // Step 2: Generate new key pair for SSL certificate    val keyPair = generateKey("RSA")    // Step 3: Create CSR (Certificate Signing Request)    val csr = createCSR(keyPair, s"CN=hydra_server_$SERVER_ID, O=Hydra, C=UK", "RSA")    // Step 4: Sign the CSR with the Root CA to generate the SSL certificate    val sslCertificate = signCertificate(csr, rootCACertificate, rootCAPrivateKey)

What I've Tried:

After consulting chatGPT, I tried the command openssl s_client -connect 192.168.0.4:443 -showcerts

The output of this command can be found here.

This helped me to verify that nginx is in fact sending the entire chain, in the correct order (can be confirmed by date - the rootCA (certificate 1 in the output) was generated on 7/2/2025, the server certificate (certificate 0) was generated today.

So what am I doing wrong/missing from my setup?


Viewing all articles
Browse latest Browse all 1534

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>