org.bouncycastle.jsse.provider.ProvTlsClient Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of impersonator Show documentation
Show all versions of impersonator Show documentation
Spoof TLS/JA3/JA4 and HTTP/2 fingerprints in Java
package org.bouncycastle.jsse.provider;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.jsse.BCSNIHostName;
import org.bouncycastle.jsse.BCSNIServerName;
import org.bouncycastle.jsse.BCX509Key;
import org.bouncycastle.jsse.provider.SignatureSchemeInfo.PerConnection;
import org.bouncycastle.tls.AlertDescription;
import org.bouncycastle.tls.AlertLevel;
import org.bouncycastle.tls.CertificateRequest;
import org.bouncycastle.tls.CertificateStatusRequest;
import org.bouncycastle.tls.CertificateStatusRequestItemV2;
import org.bouncycastle.tls.CertificateStatusType;
import org.bouncycastle.tls.DefaultTlsClient;
import org.bouncycastle.tls.IdentifierType;
import org.bouncycastle.tls.OCSPStatusRequest;
import org.bouncycastle.tls.ProtocolName;
import org.bouncycastle.tls.ProtocolVersion;
import org.bouncycastle.tls.SecurityParameters;
import org.bouncycastle.tls.ServerName;
import org.bouncycastle.tls.SessionParameters;
import org.bouncycastle.tls.SignatureAlgorithm;
import org.bouncycastle.tls.SignatureAndHashAlgorithm;
import org.bouncycastle.tls.TlsAuthentication;
import org.bouncycastle.tls.TlsContext;
import org.bouncycastle.tls.TlsCredentials;
import org.bouncycastle.tls.TlsDHGroupVerifier;
import org.bouncycastle.tls.TlsExtensionsUtils;
import org.bouncycastle.tls.TlsFatalAlert;
import org.bouncycastle.tls.TlsServerCertificate;
import org.bouncycastle.tls.TlsSession;
import org.bouncycastle.tls.TlsUtils;
import org.bouncycastle.tls.TrustedAuthority;
import org.bouncycastle.tls.crypto.impl.jcajce.JcaTlsCrypto;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.IPAddress;
import org.bouncycastle.util.encoders.Hex;
import java.io.IOException;
import java.security.Principal;
import java.security.cert.X509Certificate;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
class ProvTlsClient
extends DefaultTlsClient
implements ProvTlsPeer
{
private static final Logger LOG = Logger.getLogger(ProvTlsClient.class.getName());
private static final boolean provClientEnableCA = PropertyUtils
.getBooleanSystemProperty("jdk.tls.client.enableCAExtension", false);
private static final boolean provClientEnableSessionResumption = PropertyUtils
.getBooleanSystemProperty("org.bouncycastle.jsse.client.enableSessionResumption", true);
private static final boolean provClientEnableStatusRequest = PropertyUtils
.getBooleanSystemProperty("jdk.tls.client.enableStatusRequestExtension", true);
private static final boolean provClientEnableTrustedCAKeys = PropertyUtils
.getBooleanSystemProperty("org.bouncycastle.jsse.client.enableTrustedCAKeysExtension", false);
private static final boolean provClientOmitSigAlgsCert = PropertyUtils
.getBooleanSystemProperty("org.bouncycastle.jsse.client.omitSigAlgsCertExtension", true);
private static final boolean provEnableSNIExtension = PropertyUtils
.getBooleanSystemProperty("jsse.enableSNIExtension", true);
protected final String clientID;
protected final ProvTlsManager manager;
protected final ProvSSLParameters sslParameters;
protected final JsseSecurityParameters jsseSecurityParameters = new JsseSecurityParameters();
protected ProvSSLSession sslSession = null;
protected boolean handshakeComplete = false;
ProvTlsClient(ProvTlsManager manager, ProvSSLParameters sslParameters)
{
super(manager.getContextData().getCrypto());
this.clientID = JsseUtils.getPeerID("client", manager);
this.manager = manager;
this.sslParameters = sslParameters.copyForConnection();
}
public String getID()
{
return clientID;
}
public ProvSSLSession getSession()
{
return sslSession;
}
public TlsContext getTlsContext()
{
return context;
}
@Override
protected Vector getCertificateAuthorities()
{
if (provClientEnableCA)
{
/*
* TODO[tls13] Avoid fetching the CAs more than once if this method and
* getTrustedCAIndication are both called.
*/
return JsseUtils.getCertificateAuthorities(manager.getContextData().getX509TrustManager());
}
return null;
}
@Override
protected CertificateStatusRequest getCertificateStatusRequest()
{
if (!provClientEnableStatusRequest)
{
return null;
}
// JSSE API provides no way to specify responders or extensions, so use default request
OCSPStatusRequest ocspStatusRequest = new OCSPStatusRequest(null, null);
return new CertificateStatusRequest(CertificateStatusType.ocsp, ocspStatusRequest);
}
@Override
protected Vector getMultiCertStatusRequest()
{
if (!provClientEnableStatusRequest)
{
return null;
}
// JSSE API provides no way to specify responders or extensions, so use default request
OCSPStatusRequest ocspStatusRequest = new OCSPStatusRequest(null, null);
Vector result = new Vector(2);
result.add(new CertificateStatusRequestItemV2(CertificateStatusType.ocsp_multi, ocspStatusRequest));
result.add(new CertificateStatusRequestItemV2(CertificateStatusType.ocsp, ocspStatusRequest));
return result;
}
@Override
protected Vector getProtocolNames()
{
return JsseUtils.getProtocolNames(sslParameters.getApplicationProtocols());
}
@Override
protected Vector getSupportedGroups(@SuppressWarnings("rawtypes") Vector namedGroupRolesRaw)
{
// NOTE: Ignore roles; BCJSSE determines supported groups BEFORE signature schemes and cipher suites
// @SuppressWarnings("unchecked")
// Vector namedGroupRoles = namedGroupRolesRaw;
return NamedGroupInfo.getSupportedGroupsLocalClient(jsseSecurityParameters.namedGroups);
}
@Override
protected Vector getSNIServerNames()
{
if (provEnableSNIExtension)
{
List sniServerNames = sslParameters.getServerNames();
if (null == sniServerNames)
{
String peerHostSNI = manager.getPeerHostSNI();
/*
* TODO[jsse] Consider removing the restriction that the name must contain a '.'
* character, which is currently there for compatibility with SunJSSE.
*/
if (null != peerHostSNI && peerHostSNI.indexOf('.') > 0 && !IPAddress.isValid(peerHostSNI))
{
try
{
sniServerNames = Collections.singletonList(new BCSNIHostName(peerHostSNI));
}
catch (RuntimeException e)
{
LOG.fine(clientID + ": Failed to add peer host as default SNI host_name: " + peerHostSNI);
}
}
}
// NOTE: We follow SunJSSE behaviour and disable SNI if there are no server names to send
if (null != sniServerNames && !sniServerNames.isEmpty())
{
Vector serverNames = new Vector(sniServerNames.size());
for (BCSNIServerName sniServerName : sniServerNames)
{
serverNames.add(new ServerName((short)sniServerName.getType(), sniServerName.getEncoded()));
}
return serverNames;
}
}
return null;
}
@Override
protected int[] getSupportedCipherSuites()
{
return manager.getContextData().getContext().getActiveCipherSuites(getCrypto(), sslParameters,
getProtocolVersions());
}
@Override
protected Vector getSupportedSignatureAlgorithms()
{
return jsseSecurityParameters.signatureSchemes.getLocalSignatureAndHashAlgorithms();
}
@Override
protected Vector getSupportedSignatureAlgorithmsCert()
{
Vector result = jsseSecurityParameters.signatureSchemes
.getLocalSignatureAndHashAlgorithmsCert();
if (result == null && !provClientOmitSigAlgsCert)
{
result = jsseSecurityParameters.signatureSchemes.getLocalSignatureAndHashAlgorithms();
}
return result;
}
@Override
protected ProtocolVersion[] getSupportedVersions()
{
return manager.getContextData().getContext().getActiveProtocolVersions(sslParameters);
}
@Override
protected Vector getTrustedCAIndication()
{
if (provClientEnableTrustedCAKeys)
{
Vector certificateAuthorities = JsseUtils
.getCertificateAuthorities(manager.getContextData().getX509TrustManager());
if (null != certificateAuthorities)
{
Vector trustedCAKeys = new Vector(certificateAuthorities.size());
for (X500Name certificateAuthority : certificateAuthorities)
{
trustedCAKeys.add(new TrustedAuthority(IdentifierType.x509_name, certificateAuthority));
}
return trustedCAKeys;
}
}
return null;
}
@Override
public boolean allowLegacyResumption()
{
return JsseUtils.allowLegacyResumption();
}
public synchronized boolean isHandshakeComplete()
{
return handshakeComplete;
}
@Override
public TlsDHGroupVerifier getDHGroupVerifier()
{
return new ProvDHGroupVerifier();
}
public TlsAuthentication getAuthentication() throws IOException
{
return new TlsAuthentication()
{
public TlsCredentials getClientCredentials(CertificateRequest certificateRequest) throws IOException
{
final ContextData contextData = manager.getContextData();
final SecurityParameters securityParameters = context.getSecurityParametersHandshake();
final ProtocolVersion negotiatedVersion = securityParameters.getNegotiatedVersion();
final boolean isTLSv13 = TlsUtils.isTLSv13(negotiatedVersion);
// Setup the peer supported signature schemes
{
@SuppressWarnings("unchecked")
Vector serverSigAlgs = (Vector)
securityParameters.getServerSigAlgs();
@SuppressWarnings("unchecked")
Vector serverSigAlgsCert = (Vector)
securityParameters.getServerSigAlgsCert();
/*
* TODO[tls13] Legacy schemes (cert-only for TLS 1.3) complicate these conversions. Consider which
* (if any) of these should be constrained by locally enabled schemes (especially once
* jdk.tls.signatureSchemes support added).
*/
List peerSigSchemes = contextData.getSignatureSchemes(serverSigAlgs);
List peerSigSchemesCert = null;
if (serverSigAlgsCert != serverSigAlgs)
{
peerSigSchemesCert = contextData.getSignatureSchemes(serverSigAlgsCert);
}
jsseSecurityParameters.signatureSchemes.notifyPeerData(peerSigSchemes, peerSigSchemesCert);
if (LOG.isLoggable(Level.FINEST))
{
{
String title = clientID + " peer signature_algorithms";
LOG.finest(JsseUtils.getSignatureAlgorithmsReport(title, peerSigSchemes));
}
if (peerSigSchemesCert != null)
{
String title = clientID + " peer signature_algorithms_cert";
LOG.finest(JsseUtils.getSignatureAlgorithmsReport(title, peerSigSchemesCert));
}
}
}
if (DummyX509KeyManager.INSTANCE == contextData.getX509KeyManager())
{
return null;
}
@SuppressWarnings("unchecked")
Principal[] issuers = JsseUtils.toX500Principals(certificateRequest.getCertificateAuthorities());
byte[] certificateRequestContext = certificateRequest.getCertificateRequestContext();
if (isTLSv13 != (null != certificateRequestContext))
{
throw new TlsFatalAlert(AlertDescription.internal_error);
}
short[] certificateTypes = certificateRequest.getCertificateTypes();
if (isTLSv13 != (null == certificateTypes))
{
throw new TlsFatalAlert(AlertDescription.internal_error);
}
if (isTLSv13)
{
return selectClientCredentials13(issuers, certificateRequestContext);
}
else if (TlsUtils.isSignatureAlgorithmsExtensionAllowed(negotiatedVersion))
{
return selectClientCredentials12(issuers, certificateTypes);
}
else
{
return selectClientCredentialsLegacy(issuers, certificateTypes);
}
}
public void notifyServerCertificate(TlsServerCertificate serverCertificate) throws IOException
{
if (null == serverCertificate || null == serverCertificate.getCertificate()
|| serverCertificate.getCertificate().isEmpty())
{
throw new TlsFatalAlert(AlertDescription.handshake_failure);
}
X509Certificate[] chain = JsseUtils.getX509CertificateChain(getCrypto(),
serverCertificate.getCertificate());
String authType = JsseUtils.getAuthTypeServer(
context.getSecurityParametersHandshake().getKeyExchangeAlgorithm());
jsseSecurityParameters.statusResponses = JsseUtils.getStatusResponses(
serverCertificate.getCertificateStatus());
manager.checkServerTrusted(chain, authType);
}
};
}
@Override
public JcaTlsCrypto getCrypto()
{
return manager.getContextData().getCrypto();
}
@Override
public int getMaxCertificateChainLength()
{
return JsseUtils.getMaxCertificateChainLength();
}
@Override
public int getMaxHandshakeMessageSize()
{
return JsseUtils.getMaxHandshakeMessageSize();
}
@Override
public TlsSession getSessionToResume()
{
if (provClientEnableSessionResumption)
{
ProvSSLSession availableSSLSession = sslParameters.getSessionToResume();
if (null == availableSSLSession)
{
ProvSSLSessionContext sslSessionContext = manager.getContextData().getClientSessionContext();
availableSSLSession = sslSessionContext.getSessionImpl(manager.getPeerHost(), manager.getPeerPort());
}
if (null != availableSSLSession)
{
TlsSession sessionToResume = availableSSLSession.getTlsSession();
SessionParameters resumableSessionParameters = getResumableSessionParameters(availableSSLSession,
sessionToResume);
if (null != resumableSessionParameters)
{
this.sslSession = availableSSLSession;
if (!manager.getEnableSessionCreation())
{
// If session creation is disabled, only offer the session cipher suite.
this.cipherSuites = new int[]{ resumableSessionParameters.getCipherSuite() };
}
return sessionToResume;
}
}
}
JsseUtils.checkSessionCreationEnabled(manager);
return null;
}
@Override
public void notifyAlertRaised(short alertLevel, short alertDescription, String message, Throwable cause)
{
super.notifyAlertRaised(alertLevel, alertDescription, message, cause);
Level level = alertLevel == AlertLevel.warning ? Level.FINE
: alertDescription == AlertDescription.internal_error ? Level.WARNING
: Level.INFO;
if (LOG.isLoggable(level))
{
String msg = JsseUtils.getAlertRaisedLogMessage(clientID, alertLevel, alertDescription);
if (message != null)
{
msg = msg + ": " + message;
}
LOG.log(level, msg, cause);
}
}
@Override
public void notifyAlertReceived(short alertLevel, short alertDescription)
{
super.notifyAlertReceived(alertLevel, alertDescription);
Level level = alertLevel == AlertLevel.warning ? Level.FINE
: Level.INFO;
if (LOG.isLoggable(level))
{
String msg = JsseUtils.getAlertReceivedLogMessage(clientID, alertLevel, alertDescription);
LOG.log(level, msg);
}
}
@Override
public void notifyConnectionClosed()
{
super.notifyConnectionClosed();
if (LOG.isLoggable(Level.FINE))
{
LOG.fine(clientID + " disconnected from " + JsseUtils.getPeerReport(manager));
}
}
@Override
public void notifyHandshakeBeginning() throws IOException
{
super.notifyHandshakeBeginning();
if (LOG.isLoggable(Level.FINE))
{
LOG.fine(clientID + " opening connection to " + JsseUtils.getPeerReport(manager));
}
ContextData contextData = manager.getContextData();
ProtocolVersion[] activeProtocolVersions = getProtocolVersions();
jsseSecurityParameters.namedGroups = contextData.getNamedGroupsClient(sslParameters, activeProtocolVersions);
jsseSecurityParameters.signatureSchemes = contextData.getSignatureSchemesClient(sslParameters,
activeProtocolVersions, jsseSecurityParameters.namedGroups);
}
@Override
public synchronized void notifyHandshakeComplete() throws IOException
{
super.notifyHandshakeComplete();
this.handshakeComplete = true;
if (LOG.isLoggable(Level.FINE))
{
LOG.fine(clientID + " established connection with " + JsseUtils.getPeerReport(manager));
}
TlsSession connectionTlsSession = context.getSession();
if (null == sslSession || sslSession.getTlsSession() != connectionTlsSession)
{
ProvSSLSessionContext sslSessionContext = manager.getContextData().getClientSessionContext();
String peerHost = manager.getPeerHost();
int peerPort = manager.getPeerPort();
JsseSessionParameters jsseSessionParameters = new JsseSessionParameters(
sslParameters.getEndpointIdentificationAlgorithm(), null);
// TODO[tls13] Resumption/PSK
boolean addToCache = provClientEnableSessionResumption && !TlsUtils.isTLSv13(context);
this.sslSession = sslSessionContext.reportSession(peerHost, peerPort, connectionTlsSession,
jsseSessionParameters, addToCache);
}
manager.notifyHandshakeComplete(new ProvSSLConnection(this));
}
@Override
public void notifySecureRenegotiation(boolean secureRenegotiation) throws IOException
{
if (!secureRenegotiation)
{
boolean allowLegacyHelloMessages = PropertyUtils.getBooleanSystemProperty(
"sun.security.ssl.allowLegacyHelloMessages", true);
if (!allowLegacyHelloMessages)
{
throw new TlsFatalAlert(AlertDescription.handshake_failure);
}
}
}
@Override
public void notifySelectedCipherSuite(int selectedCipherSuite)
{
String selectedCipherSuiteName = manager.getContextData().getContext()
.validateNegotiatedCipherSuite(sslParameters, selectedCipherSuite);
if (LOG.isLoggable(Level.FINE))
{
LOG.fine(clientID + " notified of selected cipher suite: " + selectedCipherSuiteName);
}
super.notifySelectedCipherSuite(selectedCipherSuite);
}
@Override
public void notifyServerVersion(ProtocolVersion serverVersion) throws IOException
{
String serverVersionName = manager.getContextData().getContext().validateNegotiatedProtocol(sslParameters,
serverVersion);
if (LOG.isLoggable(Level.FINE))
{
LOG.fine(clientID + " notified of selected protocol version: " + serverVersionName);
}
super.notifyServerVersion(serverVersion);
}
@Override
public void notifySessionToResume(TlsSession session)
{
if (null == session)
{
JsseUtils.checkSessionCreationEnabled(manager);
}
super.notifySessionToResume(session);
}
@Override
public void notifySessionID(byte[] sessionID)
{
final boolean isResumed = !TlsUtils.isNullOrEmpty(sessionID) && null != sslSession
&& Arrays.areEqual(sessionID, sslSession.getId());
if (isResumed)
{
if (LOG.isLoggable(Level.FINE))
{
// -DM Hex.toHexString
LOG.fine(clientID + ": Server resumed session: " + Hex.toHexString(sessionID));
}
}
else
{
this.sslSession = null;
if (LOG.isLoggable(Level.FINE))
{
if (TlsUtils.isNullOrEmpty(sessionID))
{
LOG.fine(clientID + ": Server did not specify a session ID");
}
else
{
// -DM Hex.toHexString
LOG.fine(clientID + ": Server specified new session: " + Hex.toHexString(sessionID));
}
}
JsseUtils.checkSessionCreationEnabled(manager);
}
manager.notifyHandshakeSession(manager.getContextData().getClientSessionContext(),
context.getSecurityParametersHandshake(), jsseSecurityParameters, sslSession);
}
@Override
public void processServerExtensions(Map serverExtensions) throws IOException
{
super.processServerExtensions(serverExtensions);
SecurityParameters securityParameters = context.getSecurityParametersHandshake();
if (null != securityParameters.getClientServerNames())
{
boolean sniAccepted = TlsExtensionsUtils.hasServerNameExtensionServer(serverExtensions);
if (LOG.isLoggable(Level.FINER))
{
LOG.finer(clientID + ": Server accepted SNI?: " + sniAccepted);
}
}
}
@Override
public boolean requiresCloseNotify()
{
return JsseUtils.requireCloseNotify();
}
@Override
public boolean requiresExtendedMasterSecret()
{
return !JsseUtils.allowLegacyMasterSecret();
}
@Override
public boolean shouldUseCompatibilityMode()
{
return JsseUtils.useCompatibilityMode();
}
@Override
public boolean shouldUseExtendedMasterSecret()
{
return JsseUtils.useExtendedMasterSecret();
}
protected String[] getKeyTypesLegacy(short[] certificateTypes) throws IOException
{
String[] keyTypes = new String[certificateTypes.length];
for (int i = 0; i < certificateTypes.length; ++i)
{
// TODO[jsse] Need to also take notice of certificateRequest.getSupportedSignatureAlgorithms(), if present
keyTypes[i] = JsseUtils.getKeyTypeLegacyClient(certificateTypes[i]);
}
return keyTypes;
}
protected SessionParameters getResumableSessionParameters(ProvSSLSession provSSLSession, TlsSession tlsSession)
{
if (null == tlsSession || !tlsSession.isResumable())
{
return null;
}
// TODO[resumption] Avoid the copy somehow?
SessionParameters sessionParameters = tlsSession.exportSessionParameters();
{
if (null == sessionParameters ||
!Arrays.contains(getCipherSuites(), sessionParameters.getCipherSuite()))
{
return null;
}
ProtocolVersion sessionVersion = sessionParameters.getNegotiatedVersion();
if (!ProtocolVersion.contains(getProtocolVersions(), sessionVersion))
{
return null;
}
// TODO[tls13] Resumption/PSK
if (TlsUtils.isTLSv13(sessionVersion))
{
return null;
}
}
{
String connectionEndpointID = sslParameters.getEndpointIdentificationAlgorithm();
if (null != connectionEndpointID)
{
JsseSessionParameters jsseSessionParameters = provSSLSession.getJsseSessionParameters();
String sessionEndpointID = jsseSessionParameters.getEndpointIDAlgorithm();
if (!connectionEndpointID.equalsIgnoreCase(sessionEndpointID))
{
if (LOG.isLoggable(Level.FINER))
{
LOG.finer(clientID + ": Session not resumable - endpoint ID algorithm mismatch; connection: "
+ connectionEndpointID + ", session: " + sessionEndpointID);
}
return null;
}
}
}
return sessionParameters;
}
protected TlsCredentials selectClientCredentials12(Principal[] issuers, short[] certificateTypes)
throws IOException
{
/*
* RFC 5246 7.4.4 The end-entity certificate provided by the client MUST contain a key that
* is compatible with certificate_types. If the key is a signature key, it MUST be usable
* with some hash/signature algorithm pair in supported_signature_algorithms.
*/
PerConnection signatureSchemes = jsseSecurityParameters.signatureSchemes;
LinkedHashMap keyTypeMap = new LinkedHashMap();
for (SignatureSchemeInfo signatureSchemeInfo : signatureSchemes.getPeerSigSchemes())
{
String keyType = signatureSchemeInfo.getKeyType();
if (keyTypeMap.containsKey(keyType))
{
continue;
}
short signatureAlgorithm = signatureSchemeInfo.getSignatureAlgorithm();
short certificateType = SignatureAlgorithm.getClientCertificateType(signatureAlgorithm);
if (certificateType < 0 || !Arrays.contains(certificateTypes, certificateType))
{
continue;
}
if (!signatureSchemeInfo.isSupportedPre13() ||
!signatureSchemes.hasLocalSignatureScheme(signatureSchemeInfo))
{
continue;
}
keyTypeMap.put(keyType, signatureSchemeInfo);
}
if (keyTypeMap.isEmpty())
{
if (LOG.isLoggable(Level.FINE))
{
LOG.fine(clientID + " (1.2) found no usable signature schemes");
}
return null;
}
String[] keyTypes = keyTypeMap.keySet().toArray(TlsUtils.EMPTY_STRINGS);
BCX509Key x509Key = manager.chooseClientKey(keyTypes, issuers);
if (null == x509Key)
{
handleKeyManagerMisses(keyTypeMap, null);
if (LOG.isLoggable(Level.FINE))
{
LOG.fine(clientID + " (1.2) did not select any credentials");
}
return null;
}
String selectedKeyType = x509Key.getKeyType();
handleKeyManagerMisses(keyTypeMap, selectedKeyType);
SignatureSchemeInfo selectedSignatureSchemeInfo = keyTypeMap.get(selectedKeyType);
if (null == selectedSignatureSchemeInfo)
{
throw new TlsFatalAlert(AlertDescription.internal_error, "Key manager returned invalid key type");
}
if (LOG.isLoggable(Level.FINE))
{
LOG.fine(clientID + " (1.2) selected credentials for signature scheme '" + selectedSignatureSchemeInfo
+ "' (keyType '" + selectedKeyType + "'), with private key algorithm '"
+ JsseUtils.getPrivateKeyAlgorithm(x509Key.getPrivateKey()) + "'");
}
return JsseUtils.createCredentialedSigner(context, getCrypto(), x509Key,
selectedSignatureSchemeInfo.getSignatureAndHashAlgorithm());
}
protected TlsCredentials selectClientCredentials13(Principal[] issuers, byte[] certificateRequestContext)
throws IOException
{
PerConnection signatureSchemes = jsseSecurityParameters.signatureSchemes;
LinkedHashMap keyTypeMap = new LinkedHashMap();
for (SignatureSchemeInfo signatureSchemeInfo : signatureSchemes.getPeerSigSchemes())
{
String keyType = signatureSchemeInfo.getKeyType13();
if (keyTypeMap.containsKey(keyType))
{
continue;
}
if (!signatureSchemeInfo.isSupportedPost13() ||
!signatureSchemes.hasLocalSignatureScheme(signatureSchemeInfo))
{
continue;
}
keyTypeMap.put(keyType, signatureSchemeInfo);
}
if (keyTypeMap.isEmpty())
{
if (LOG.isLoggable(Level.FINE))
{
LOG.fine(clientID + " (1.3) found no usable signature schemes");
}
return null;
}
String[] keyTypes = keyTypeMap.keySet().toArray(TlsUtils.EMPTY_STRINGS);
BCX509Key x509Key = manager.chooseClientKey(keyTypes, issuers);
if (null == x509Key)
{
handleKeyManagerMisses(keyTypeMap, null);
if (LOG.isLoggable(Level.FINE))
{
LOG.fine(clientID + " (1.3) did not select any credentials");
}
return null;
}
String selectedKeyType = x509Key.getKeyType();
handleKeyManagerMisses(keyTypeMap, selectedKeyType);
SignatureSchemeInfo selectedSignatureSchemeInfo = keyTypeMap.get(selectedKeyType);
if (null == selectedSignatureSchemeInfo)
{
throw new TlsFatalAlert(AlertDescription.internal_error, "Key manager returned invalid key type");
}
if (LOG.isLoggable(Level.FINE))
{
LOG.fine(clientID + " (1.3) selected credentials for signature scheme '" + selectedSignatureSchemeInfo
+ "' (keyType '" + selectedKeyType + "'), with private key algorithm '"
+ JsseUtils.getPrivateKeyAlgorithm(x509Key.getPrivateKey()) + "'");
}
return JsseUtils.createCredentialedSigner13(context, getCrypto(), x509Key,
selectedSignatureSchemeInfo.getSignatureAndHashAlgorithm(), certificateRequestContext);
}
protected TlsCredentials selectClientCredentialsLegacy(Principal[] issuers, short[] certificateTypes)
throws IOException
{
String[] keyTypes = getKeyTypesLegacy(certificateTypes);
if (keyTypes.length < 1)
{
return null;
}
BCX509Key x509Key = manager.chooseClientKey(keyTypes, issuers);
if (null == x509Key)
{
return null;
}
return JsseUtils.createCredentialedSigner(context, getCrypto(), x509Key, null);
}
private void handleKeyManagerMisses(LinkedHashMap keyTypeMap, String selectedKeyType)
{
for (Map.Entry entry : keyTypeMap.entrySet())
{
String keyType = entry.getKey();
if (keyType.equals(selectedKeyType))
{
break;
}
if (LOG.isLoggable(Level.FINER))
{
SignatureSchemeInfo signatureSchemeInfo = entry.getValue();
LOG.finer(clientID + " found no credentials for signature scheme '" + signatureSchemeInfo
+ "' (keyType '" + keyType + "')");
}
}
}
}