Ich versuche, ein clientseitiges Zertifikat mit mTls 1.3 an den Nginx-Server zu senden. Ich verwende mein selbstsigniertes Zertifikat aus meinem Java-Keystore. Ich habe Firefoxnginx bereits manuell mit dem exportierten Schlüsselpaar aus meinem Keystore getestet. Nginx akzeptiert das.
Aber bei meiner Java Bouncy Castle-Implementierung schlägt es fehl. Ich habe mehrere Tage damit verbracht, konnte aber keine Lösung finden, um das Client-Zertifikat ordnungsgemäß zu senden. Wenn ich die Client-Überprüfung auf Nginx deaktiviere, funktioniert es und dies zeigt, dass mein Zertifikat nicht ordnungsgemäß gesendet wird.
import TlsFatalAlertExtendedException;
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.tls.*;
import org.bouncycastle.tls.crypto.TlsCertificate;
import org.bouncycastle.tls.crypto.TlsCryptoParameters;
import org.bouncycastle.tls.crypto.impl.bc.BcDefaultTlsCredentialedSigner;
import org.bouncycastle.tls.crypto.impl.bc.BcTlsCrypto;
import org.bouncycastle.crypto.util.PrivateKeyFactory;
import javax.net.ssl.HandshakeCompletedListener;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import java.io.*;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.PrivateKey;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Hashtable;
import java.util.Vector;
@Slf4j
public class CustomSSLSocket extends SSLSocket {
private static final int INT_3 = 3; // Unused, consider removing if not needed elsewhere
private final TlsClientProtocol tlsClientProtocol;
private final KeyStoreManager keyStoreManager;
private final String host;
private Certificate[] peertCerts; // Initialized to null, will be set after validation
private final BcTlsCrypto crypto;
public CustomSSLSocket(TlsClientProtocol tlsClientProtocol, String host, KeyStoreManager keyStoreManager) {
System.out.println("Creating CustomSSLSocket for mTLS...");
// peertCerts is now initialized to null, will be set after server cert validation
this.host = host;
this.keyStoreManager = keyStoreManager;
this.tlsClientProtocol = tlsClientProtocol;
this.crypto = new BcTlsCrypto(new SecureRandom());
}
// Setter for peer certificates, called after successful validation
private void setPeerCertificates(Certificate[] certs) {
this.peertCerts = certs;
}
@Override
public InputStream getInputStream() {
return tlsClientProtocol.getInputStream();
}
@Override
public OutputStream getOutputStream() {
return tlsClientProtocol.getOutputStream();
}
@Override
public synchronized void close() throws IOException {
tlsClientProtocol.close();
}
@Override
public void addHandshakeCompletedListener(HandshakeCompletedListener arg0) {
// intentionally empty
}
@Override
public boolean getEnableSessionCreation() {
return false;
}
@Override
public String[] getEnabledCipherSuites() {
return new String[]{};
}
@Override
public String[] getEnabledProtocols() {
return new String[]{};
}
@Override
public boolean getNeedClientAuth() {
return false;
}
@Override
public SSLSession getSession() {
// Ensure peertCerts is not null, though it should be set by now if handshake succeeded
return new CustomSSLSession(peertCerts != null ? peertCerts : new Certificate[0]);
}
@Override
public String[] getSupportedProtocols() {
return new String[]{};
}
@Override
public boolean getUseClientMode() {
return false;
}
@Override
public boolean getWantClientAuth() {
return false;
}
@Override
public void removeHandshakeCompletedListener(HandshakeCompletedListener arg0) {
// intentionally empty
}
@Override
public void setEnableSessionCreation(boolean arg0) {
// intentionally empty
}
@Override
public void setEnabledCipherSuites(String[] arg0) {
// intentionally empty
}
@Override
public void setEnabledProtocols(String[] arg0) {
// intentionally empty
}
@Override
public void setNeedClientAuth(boolean arg0) {
// intentionally empty
}
@Override
public void setUseClientMode(boolean arg0) {
// intentionally empty
}
@Override
public void setWantClientAuth(boolean arg0) {
// intentionally empty
}
@Override
public String[] getSupportedCipherSuites() {
return new String[]{};
}
@Override
public void startHandshake() throws IOException {
System.out.println("Starting handshake for mTLS...");
// Always use this.crypto instance, not a new one!
tlsClientProtocol.connect(new MyDefaultTlsClient(this.crypto, this.keyStoreManager, this.host));
}
// This method now correctly throws TlsFatalAlertExtendedException if the cert is not trusted.
public void validateCertificate(TlsServerCertificate cert)
throws IOException, CertificateException, KeyStoreException, TlsFatalAlertExtendedException {
System.out.println("Validating server certificate for mTLS...");
byte[] encoded = cert.getCertificate().getCertificateList()[0].getEncoded();
Certificate jsCert =
CertificateFactory.getInstance("X.509")
.generateCertificate(new ByteArrayInputStream(encoded));
String alias = keyStoreManager.getCertificateAlias(jsCert);
if (alias == null) {
System.out.println("Server certificate validation failed: Certificate not trusted.");
// CRITICAL FIX: UNCOMMENT THIS LINE to properly fail the handshake
throw new TlsFatalAlertExtendedException(AlertDescription.bad_certificate, jsCert);
// Removed the problematic dynamic storing of untrusted certificates.
// If you need to trust a certificate, it should be added to the KeyStoreManager's trust store beforehand.
} else {
System.out.println("Server certificate trusted via alias: " + alias);
}
}
private class MyDefaultTlsClient extends DefaultTlsClient {
private final KeyStoreManager ksm;
private final String hostName;
private TlsContext tlsContext;
public MyDefaultTlsClient(BcTlsCrypto crypto, KeyStoreManager ksm, String hostName) {
super(crypto);
this.ksm = ksm;
this.hostName = hostName;
}
@Override
public void init(TlsClientContext context) {
this.tlsContext = context;
super.init(context);
}
@Override
public Hashtable getClientExtensions() throws IOException {
Hashtable clientExtensions = TlsExtensionsUtils.ensureExtensionsInitialised(super.getClientExtensions());
{
/*
* NOTE: If you are copying test code, do not blindly set these extensions in your own client.
* These are often for specific testing scenarios or legacy compatibility.
* For a general client, you might not need all of them.
*/
TlsExtensionsUtils.addMaxFragmentLengthExtension(clientExtensions, MaxFragmentLength.pow2_9);
TlsExtensionsUtils.addPaddingExtension(clientExtensions, context.getCrypto().getSecureRandom().nextInt(16));
TlsExtensionsUtils.addTruncatedHMacExtension(clientExtensions);
}
return clientExtensions;
}
@Override
public TlsAuthentication getAuthentication() {
System.out.println("Getting TLS authentication for mTLS...");
// IMPORTANT: Pass the BC handshake context, BC crypto, and KeyStoreManager
return new MyTlsAuthentication(tlsContext, (BcTlsCrypto) getCrypto(), ksm);
}
private class MyTlsAuthentication implements TlsAuthentication {
private final TlsContext tlsContext;
private final BcTlsCrypto crypto;
private final KeyStoreManager keyStoreManager;
public MyTlsAuthentication(TlsContext ctx, BcTlsCrypto crypto, KeyStoreManager ksm) {
this.tlsContext = ctx;
this.crypto = crypto;
this.keyStoreManager = ksm;
}
@Override
public void notifyServerCertificate(TlsServerCertificate serverCertificate) throws IOException {
System.out.println("Notifying server certificate for mTLS...");
try {
boolean isEmpty =
serverCertificate == null
|| serverCertificate.getCertificate() == null
|| serverCertificate.getCertificate().isEmpty();
if (isEmpty) {
throw new TlsFatalAlert(AlertDescription.bad_certificate);
}
// Validate the server certificate
validateCertificate(serverCertificate);
// If validation succeeds, store the peer certificates for the SSLSession
TlsCertificate[] bcCertList = serverCertificate.getCertificate().getCertificateList();
Certificate[] javaCertList = new Certificate[bcCertList.length];
for (int i = 0; i < bcCertList.length; i++) {
javaCertList[i] = CertificateFactory.getInstance("X.509")
.generateCertificate(new ByteArrayInputStream(bcCertList[i].getEncoded()));
}
CustomSSLSocket.this.setPeerCertificates(javaCertList); // Update the outer class's peertCerts
} catch (TlsFatalAlert e) {
// CRITICAL FIX: Re-throw TlsFatalAlert directly to ensure Bouncy Castle handles it
log.error("TLS Fatal Alert during server certificate notification: {}", e.getMessage(), e);
throw e;
} catch (Exception e) {
// For other unexpected exceptions, wrap in IOException
log.error("Error during server certificate notification: {}", e.getMessage(), e);
throw new IOException("Error during server certificate notification: " + e.getMessage(), e);
}
}
@Override
public TlsCredentials getClientCredentials(CertificateRequest certificateRequest) {
System.out.println("Getting client credentials for mTLS...");
try {
// 1. Retrieve keystore credentials
String alias = "CN-ClientCertificate"; // Ensure this alias exists in your KeyStoreManager
KeyStore keyStore = keyStoreManager.getKeyStore();
char[] password = keyStoreManager.getKeystorePass().toCharArray();
// 2. Extract chain and key
java.security.cert.Certificate[] certChain = keyStore.getCertificateChain(alias);
if (certChain == null || certChain.length == 0) {
log.warn("Client certificate chain not found for alias: {}. Returning null credentials.", alias);
// If client cert is required by server, this will cause handshake failure.
// Consider throwing TlsFatalAlert if client cert is mandatory for your use case.
return null;
}
for (Certificate cert : certChain) {
System.out.println("Chain cert subject: " + ((X509Certificate) cert).getSubjectX500Principal());
}
PrivateKey privateKey = (PrivateKey) keyStore.getKey(alias, password);
if (privateKey == null) {
log.warn("Client private key not found for alias: {}. Returning null credentials.", alias);
// Similar to above, consider throwing TlsFatalAlert if private key is mandatory.
return null;
}
// 3. Convert certificates to BC format
TlsCertificate[] bcTlsCertChain = new TlsCertificate[certChain.length];
for (int i = 0; i < certChain.length; i++) {
bcTlsCertChain[i] = crypto.createCertificate(certChain[i].getEncoded());
}
org.bouncycastle.tls.Certificate bcTlsCertificate = new org.bouncycastle.tls.Certificate(bcTlsCertChain);
AsymmetricKeyParameter bcKeyParam = PrivateKeyFactory.createKey(privateKey.getEncoded());
// 4. Choose signature algorithm
SignatureAndHashAlgorithm sigAlg = null;
Vector algs = certificateRequest.getSupportedSignatureAlgorithms();
if (algs != null) {
for (Object a : algs) {
SignatureAndHashAlgorithm alg = (SignatureAndHashAlgorithm) a;
// Check for RSA-PSS (Case 4 / SignatureAlgorithm.rsa_pss_rsae_sha256)
// Prioritize modern, secure algorithms
if (alg.getSignature() == SignatureAlgorithm.rsa_pss_rsae_sha256 && alg.getHash() == HashAlgorithm.sha256) {
sigAlg = alg;
System.out.println("Selected modern signature algorithm: RSA-PSS with SHA256");
break;
}
// Add other preferred algorithms if RSA-PSS is not available
if (alg.getSignature() == SignatureAlgorithm.rsa && alg.getHash() == HashAlgorithm.sha256) {
sigAlg = alg; // Fallback to RSA/SHA256
}
}
}
// If no suitable algorithm was found in the request, default to a common one
if (sigAlg == null) {
sigAlg = new SignatureAndHashAlgorithm(HashAlgorithm.sha256, SignatureAlgorithm.rsa);
System.out.println("Defaulting to standard RSA/SHA256 as no preferred algorithm was found in request.");
}
System.out.println("Client will use signature algorithm: " + SignatureAlgorithm.getName(sigAlg.getSignature()) + " with hash " + HashAlgorithm.getName(sigAlg.getHash()));
// 5. Always pass the handshake's BC context!
TlsCryptoParameters cryptoParams = new TlsCryptoParameters(tlsContext);
System.out.println("Successfully obtained client credentials for mTLS.");
return new BcDefaultTlsCredentialedSigner(
cryptoParams,
crypto,
bcKeyParam,
bcTlsCertificate,
sigAlg
);
} catch (Exception e) {
log.error("Error obtaining client credentials for mTLS: {}", e.getMessage(), e);
// Consider throwing TlsFatalAlert here if client credentials are mandatory
return null;
}
}
}
}
}
TLSSocketConnectionFactory: Creating socket to host 192.168.178.88 on port 443
Creating CustomSSLSocket for mTLS...
Starting handshake for mTLS...
Getting TLS authentication for mTLS...
Notifying server certificate for mTLS...
Validating server certificate for mTLS...
Server certificate trusted via alias: cEbm.L3*
Getting client credentials for mTLS...
Chain cert subject: CN=MY SUBJECT CERTIFICATE
Chain cert subject: CN=MY ISSUER CERTIFICATE
Chain cert subject: CN=MY ROOT CA
Client will use signature algorithm: rsa with hash sha256
Successfully obtained client credentials for mTLS.
2026-01-15T13:26:33.899 [pool-6-thread-1] ERROR c.s.a.c.c.c.o.f.c.Cn4100ClientExceptionHandler - Request timeout when calling Cn4100Client service.: : (-1) feign.RetryableException: internal_error(80) executing GET https://192.168.178.88:443/config/restapi_version
@Slf4j public class TLSSocketConnectionFactory extends SSLSocketFactory { // ******************Adding Custom BouncyCastleProvider*********************// private final KeyStoreManager keyStoreManager; private CustomSSLSocket sslSocket;
public TLSSocketConnectionFactory(KeyStoreManager keyStoreManager) { System.out.println("TLSSocketConnectionFactory: Initializing with KeyStoreManager"); this.keyStoreManager = keyStoreManager; }
// ******************HANDSHAKE LISTENER*********************// public class TLSHandshakeListener implements HandshakeCompletedListener { @Override public void handshakeCompleted(HandshakeCompletedEvent event) { // intentionally empty } }
// ******************Adding Custom BouncyCastleProvider*********************// @Override public Socket createSocket(Socket socket, final String host, int port, boolean arg3) throws IOException { System.out.println("TLSSocketConnectionFactory: Creating socket to host " + host + " on port " + port); if (socket == null) { socket = new Socket(); // NOSONAR -- this is closed in the SSLSocket }
if (!socket.isConnected()) { socket.connect(new InetSocketAddress(host, port)); }
final TlsClientProtocol tlsClientProtocol = new TlsClientProtocol(socket.getInputStream(), socket.getOutputStream()); return createSSLSocket(host, tlsClientProtocol); }
// ******************SOCKET FACTORY METHODS*********************// @Override public String[] getDefaultCipherSuites() { return new String[]{}; }
@Override public String[] getSupportedCipherSuites() { return new String[]{}; }
@Override public Socket createSocket(String host, int port) { return null; }
@Override public Socket createSocket(InetAddress host, int port) { return null; }
@Override public Socket createSocket(String host, int port, InetAddress localHost, int localPort) { return null; }
@Override public Socket createSocket( InetAddress address, int port, InetAddress localAddress, int localPort) { return null; }
private SSLSocket createSSLSocket(final String host, final TlsClientProtocol tlsClientProtocol) { sslSocket = new CustomSSLSocket(tlsClientProtocol, host, keyStoreManager); return sslSocket; }
public CustomSSLSocket getSSLSocket(final String host, final TlsClientProtocol tlsClientProtocol) { if (sslSocket == null) { sslSocket = new CustomSSLSocket(tlsClientProtocol, host, keyStoreManager); } return sslSocket; } } [/code] und CustomSSLSocket-Klasse [code]import TlsFatalAlertExtendedException; import lombok.extern.slf4j.Slf4j; import org.bouncycastle.crypto.params.AsymmetricKeyParameter; import org.bouncycastle.tls.*; import org.bouncycastle.tls.crypto.TlsCertificate; import org.bouncycastle.tls.crypto.TlsCryptoParameters; import org.bouncycastle.tls.crypto.impl.bc.BcDefaultTlsCredentialedSigner; import org.bouncycastle.tls.crypto.impl.bc.BcTlsCrypto; import org.bouncycastle.crypto.util.PrivateKeyFactory;
@Slf4j public class CustomSSLSocket extends SSLSocket { private static final int INT_3 = 3; // Unused, consider removing if not needed elsewhere private final TlsClientProtocol tlsClientProtocol; private final KeyStoreManager keyStoreManager; private final String host; private Certificate[] peertCerts; // Initialized to null, will be set after validation private final BcTlsCrypto crypto;
public CustomSSLSocket(TlsClientProtocol tlsClientProtocol, String host, KeyStoreManager keyStoreManager) { System.out.println("Creating CustomSSLSocket for mTLS..."); // peertCerts is now initialized to null, will be set after server cert validation this.host = host; this.keyStoreManager = keyStoreManager; this.tlsClientProtocol = tlsClientProtocol; this.crypto = new BcTlsCrypto(new SecureRandom()); }
// Setter for peer certificates, called after successful validation private void setPeerCertificates(Certificate[] certs) { this.peertCerts = certs; }
@Override public InputStream getInputStream() { return tlsClientProtocol.getInputStream(); }
@Override public OutputStream getOutputStream() { return tlsClientProtocol.getOutputStream(); }
@Override public synchronized void close() throws IOException { tlsClientProtocol.close(); }
@Override public void addHandshakeCompletedListener(HandshakeCompletedListener arg0) { // intentionally empty }
@Override public boolean getEnableSessionCreation() { return false; }
@Override public String[] getEnabledCipherSuites() { return new String[]{}; }
@Override public String[] getEnabledProtocols() { return new String[]{}; }
@Override public boolean getNeedClientAuth() { return false; }
@Override public SSLSession getSession() { // Ensure peertCerts is not null, though it should be set by now if handshake succeeded return new CustomSSLSession(peertCerts != null ? peertCerts : new Certificate[0]); }
@Override public String[] getSupportedProtocols() { return new String[]{}; }
@Override public boolean getUseClientMode() { return false; }
@Override public boolean getWantClientAuth() { return false; }
@Override public void removeHandshakeCompletedListener(HandshakeCompletedListener arg0) { // intentionally empty }
@Override public void setEnableSessionCreation(boolean arg0) { // intentionally empty }
@Override public void setEnabledCipherSuites(String[] arg0) { // intentionally empty }
@Override public void setEnabledProtocols(String[] arg0) { // intentionally empty }
@Override public void setNeedClientAuth(boolean arg0) { // intentionally empty }
@Override public void setUseClientMode(boolean arg0) { // intentionally empty }
@Override public void setWantClientAuth(boolean arg0) { // intentionally empty }
@Override public String[] getSupportedCipherSuites() { return new String[]{}; }
@Override public void startHandshake() throws IOException { System.out.println("Starting handshake for mTLS..."); // Always use this.crypto instance, not a new one! tlsClientProtocol.connect(new MyDefaultTlsClient(this.crypto, this.keyStoreManager, this.host)); }
// This method now correctly throws TlsFatalAlertExtendedException if the cert is not trusted. public void validateCertificate(TlsServerCertificate cert) throws IOException, CertificateException, KeyStoreException, TlsFatalAlertExtendedException { System.out.println("Validating server certificate for mTLS..."); byte[] encoded = cert.getCertificate().getCertificateList()[0].getEncoded(); Certificate jsCert = CertificateFactory.getInstance("X.509") .generateCertificate(new ByteArrayInputStream(encoded)); String alias = keyStoreManager.getCertificateAlias(jsCert);
if (alias == null) { System.out.println("Server certificate validation failed: Certificate not trusted."); // CRITICAL FIX: UNCOMMENT THIS LINE to properly fail the handshake throw new TlsFatalAlertExtendedException(AlertDescription.bad_certificate, jsCert); // Removed the problematic dynamic storing of untrusted certificates. // If you need to trust a certificate, it should be added to the KeyStoreManager's trust store beforehand. } else { System.out.println("Server certificate trusted via alias: " + alias); } }
private class MyDefaultTlsClient extends DefaultTlsClient { private final KeyStoreManager ksm; private final String hostName; private TlsContext tlsContext;
@Override public Hashtable getClientExtensions() throws IOException { Hashtable clientExtensions = TlsExtensionsUtils.ensureExtensionsInitialised(super.getClientExtensions()); { /* * NOTE: If you are copying test code, do not blindly set these extensions in your own client. * These are often for specific testing scenarios or legacy compatibility. * For a general client, you might not need all of them. */ TlsExtensionsUtils.addMaxFragmentLengthExtension(clientExtensions, MaxFragmentLength.pow2_9); TlsExtensionsUtils.addPaddingExtension(clientExtensions, context.getCrypto().getSecureRandom().nextInt(16)); TlsExtensionsUtils.addTruncatedHMacExtension(clientExtensions); } return clientExtensions; }
@Override public TlsAuthentication getAuthentication() { System.out.println("Getting TLS authentication for mTLS..."); // IMPORTANT: Pass the BC handshake context, BC crypto, and KeyStoreManager return new MyTlsAuthentication(tlsContext, (BcTlsCrypto) getCrypto(), ksm); }
private class MyTlsAuthentication implements TlsAuthentication { private final TlsContext tlsContext; private final BcTlsCrypto crypto; private final KeyStoreManager keyStoreManager;
@Override public void notifyServerCertificate(TlsServerCertificate serverCertificate) throws IOException { System.out.println("Notifying server certificate for mTLS..."); try { boolean isEmpty = serverCertificate == null || serverCertificate.getCertificate() == null || serverCertificate.getCertificate().isEmpty(); if (isEmpty) { throw new TlsFatalAlert(AlertDescription.bad_certificate); }
// Validate the server certificate validateCertificate(serverCertificate);
// If validation succeeds, store the peer certificates for the SSLSession TlsCertificate[] bcCertList = serverCertificate.getCertificate().getCertificateList(); Certificate[] javaCertList = new Certificate[bcCertList.length]; for (int i = 0; i < bcCertList.length; i++) { javaCertList[i] = CertificateFactory.getInstance("X.509") .generateCertificate(new ByteArrayInputStream(bcCertList[i].getEncoded())); } CustomSSLSocket.this.setPeerCertificates(javaCertList); // Update the outer class's peertCerts
} catch (TlsFatalAlert e) { // CRITICAL FIX: Re-throw TlsFatalAlert directly to ensure Bouncy Castle handles it log.error("TLS Fatal Alert during server certificate notification: {}", e.getMessage(), e); throw e; } catch (Exception e) { // For other unexpected exceptions, wrap in IOException log.error("Error during server certificate notification: {}", e.getMessage(), e); throw new IOException("Error during server certificate notification: " + e.getMessage(), e); } }
@Override public TlsCredentials getClientCredentials(CertificateRequest certificateRequest) { System.out.println("Getting client credentials for mTLS..."); try { // 1. Retrieve keystore credentials String alias = "CN-ClientCertificate"; // Ensure this alias exists in your KeyStoreManager KeyStore keyStore = keyStoreManager.getKeyStore(); char[] password = keyStoreManager.getKeystorePass().toCharArray();
// 2. Extract chain and key java.security.cert.Certificate[] certChain = keyStore.getCertificateChain(alias); if (certChain == null || certChain.length == 0) { log.warn("Client certificate chain not found for alias: {}. Returning null credentials.", alias); // If client cert is required by server, this will cause handshake failure. // Consider throwing TlsFatalAlert if client cert is mandatory for your use case. return null; } for (Certificate cert : certChain) { System.out.println("Chain cert subject: " + ((X509Certificate) cert).getSubjectX500Principal()); }
PrivateKey privateKey = (PrivateKey) keyStore.getKey(alias, password); if (privateKey == null) { log.warn("Client private key not found for alias: {}. Returning null credentials.", alias); // Similar to above, consider throwing TlsFatalAlert if private key is mandatory. return null; }
// 3. Convert certificates to BC format TlsCertificate[] bcTlsCertChain = new TlsCertificate[certChain.length]; for (int i = 0; i < certChain.length; i++) { bcTlsCertChain[i] = crypto.createCertificate(certChain[i].getEncoded()); }
org.bouncycastle.tls.Certificate bcTlsCertificate = new org.bouncycastle.tls.Certificate(bcTlsCertChain); AsymmetricKeyParameter bcKeyParam = PrivateKeyFactory.createKey(privateKey.getEncoded());
// 4. Choose signature algorithm SignatureAndHashAlgorithm sigAlg = null; Vector algs = certificateRequest.getSupportedSignatureAlgorithms(); if (algs != null) { for (Object a : algs) { SignatureAndHashAlgorithm alg = (SignatureAndHashAlgorithm) a;
// Check for RSA-PSS (Case 4 / SignatureAlgorithm.rsa_pss_rsae_sha256) // Prioritize modern, secure algorithms if (alg.getSignature() == SignatureAlgorithm.rsa_pss_rsae_sha256 && alg.getHash() == HashAlgorithm.sha256) { sigAlg = alg; System.out.println("Selected modern signature algorithm: RSA-PSS with SHA256"); break; } // Add other preferred algorithms if RSA-PSS is not available if (alg.getSignature() == SignatureAlgorithm.rsa && alg.getHash() == HashAlgorithm.sha256) { sigAlg = alg; // Fallback to RSA/SHA256 } } } // If no suitable algorithm was found in the request, default to a common one if (sigAlg == null) { sigAlg = new SignatureAndHashAlgorithm(HashAlgorithm.sha256, SignatureAlgorithm.rsa); System.out.println("Defaulting to standard RSA/SHA256 as no preferred algorithm was found in request."); }
System.out.println("Client will use signature algorithm: " + SignatureAlgorithm.getName(sigAlg.getSignature()) + " with hash " + HashAlgorithm.getName(sigAlg.getHash())); // 5. Always pass the handshake's BC context! TlsCryptoParameters cryptoParams = new TlsCryptoParameters(tlsContext);
System.out.println("Successfully obtained client credentials for mTLS."); return new BcDefaultTlsCredentialedSigner( cryptoParams, crypto, bcKeyParam, bcTlsCertificate, sigAlg ); } catch (Exception e) { log.error("Error obtaining client credentials for mTLS: {}", e.getMessage(), e); // Consider throwing TlsFatalAlert here if client credentials are mandatory return null; } } } } } [/code] [b]Java-Ausgabe:[/b] [code]TLSSocketConnectionFactory: Creating socket to host 192.168.178.88 on port 443 Creating CustomSSLSocket for mTLS... Starting handshake for mTLS... Getting TLS authentication for mTLS... Notifying server certificate for mTLS... Validating server certificate for mTLS... Server certificate trusted via alias: cEbm.L3* Getting client credentials for mTLS... Chain cert subject: CN=MY SUBJECT CERTIFICATE Chain cert subject: CN=MY ISSUER CERTIFICATE Chain cert subject: CN=MY ROOT CA Client will use signature algorithm: rsa with hash sha256 Successfully obtained client credentials for mTLS. 2026-01-15T13:26:33.899 [pool-6-thread-1] ERROR c.s.a.c.c.c.o.f.c.Cn4100ClientExceptionHandler - Request timeout when calling Cn4100Client service.: : (-1) feign.RetryableException: internal_error(80) executing GET https://192.168.178.88:443/config/restapi_version [/code]
Hallo, ich versuche, ein clientseitiges Zertifikat mit mTls 1.3 an den Nginx-Server zu senden.
Ich verwende mein selbstsigniertes Zertifikat aus meinem Java-Keystore. Ich habe Firefoxnginx bereits...
Ich erhalte diesen Fehler:
Schwerwiegender Fehler: Curl ist mit Fehler Nr. 58 fehlgeschlagen: Client-Zertifikat kann nicht verwendet werden (kein Schlüssel gefunden oder falsche Passphrase?)
Ich habe die Authentifizierungsmethode von PublickeyAuthenticator.java überschrieben und beim SSH-Server registriert.
sshServer.setPublickeyAuthenticator(publicKeyAuth);