org.bouncycastle.jsse.provider.JsseUtils 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.ASN1Encodable;
import org.bouncycastle.asn1.ASN1Encoding;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ocsp.OCSPResponse;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
import org.bouncycastle.jsse.BCSNIHostName;
import org.bouncycastle.jsse.BCSNIMatcher;
import org.bouncycastle.jsse.BCSNIServerName;
import org.bouncycastle.jsse.BCStandardConstants;
import org.bouncycastle.jsse.BCX509ExtendedTrustManager;
import org.bouncycastle.jsse.BCX509Key;
import org.bouncycastle.jsse.java.security.BCCryptoPrimitive;
import org.bouncycastle.tls.AlertDescription;
import org.bouncycastle.tls.AlertLevel;
import org.bouncycastle.tls.Certificate;
import org.bouncycastle.tls.CertificateEntry;
import org.bouncycastle.tls.CertificateStatus;
import org.bouncycastle.tls.CertificateStatusType;
import org.bouncycastle.tls.ClientCertificateType;
import org.bouncycastle.tls.IdentifierType;
import org.bouncycastle.tls.KeyExchangeAlgorithm;
import org.bouncycastle.tls.NamedGroup;
import org.bouncycastle.tls.ProtocolName;
import org.bouncycastle.tls.ProtocolVersion;
import org.bouncycastle.tls.SecurityParameters;
import org.bouncycastle.tls.ServerName;
import org.bouncycastle.tls.SignatureAndHashAlgorithm;
import org.bouncycastle.tls.TlsContext;
import org.bouncycastle.tls.TlsCredentialedDecryptor;
import org.bouncycastle.tls.TlsCredentialedSigner;
import org.bouncycastle.tls.TlsUtils;
import org.bouncycastle.tls.TrustedAuthority;
import org.bouncycastle.tls.crypto.TlsCertificate;
import org.bouncycastle.tls.crypto.TlsCryptoParameters;
import org.bouncycastle.tls.crypto.impl.jcajce.JcaDefaultTlsCredentialedSigner;
import org.bouncycastle.tls.crypto.impl.jcajce.JcaTlsCertificate;
import org.bouncycastle.tls.crypto.impl.jcajce.JcaTlsCrypto;
import org.bouncycastle.tls.crypto.impl.jcajce.JceDefaultTlsCredentialedDecryptor;
import org.bouncycastle.util.encoders.Hex;
import javax.security.auth.x500.X500Principal;
import java.io.IOException;
import java.security.Key;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
abstract class JsseUtils
{
private static final boolean provTlsAllowLegacyMasterSecret =
PropertyUtils.getBooleanSystemProperty("jdk.tls.allowLegacyMasterSecret", true);
private static final boolean provTlsAllowLegacyResumption =
PropertyUtils.getBooleanSystemProperty("jdk.tls.allowLegacyResumption", false);
private static final int provTlsMaxCertificateChainLength =
PropertyUtils.getIntegerSystemProperty("jdk.tls.maxCertificateChainLength", 10, 1, Integer.MAX_VALUE);
private static final int provTlsMaxHandshakeMessageSize =
PropertyUtils.getIntegerSystemProperty("jdk.tls.maxHandshakeMessageSize", 32768, 1024, Integer.MAX_VALUE);
private static final boolean provTlsRequireCloseNotify =
PropertyUtils.getBooleanSystemProperty("com.sun.net.ssl.requireCloseNotify", true);
private static final boolean provTlsUseCompatibilityMode =
PropertyUtils.getBooleanSystemProperty("jdk.tls.client.useCompatibilityMode", true);
// TODO SunJSSE additionally checks KeyGenerator.getInstance("SunTlsExtendedMasterSecret")
private static final boolean provTlsUseExtendedMasterSecret =
PropertyUtils.getBooleanSystemProperty("jdk.tls.useExtendedMasterSecret", true);
static final Set KEY_AGREEMENT_CRYPTO_PRIMITIVES_BC =
Collections.unmodifiableSet(EnumSet.of(BCCryptoPrimitive.KEY_AGREEMENT));
static final Set KEY_ENCAPSULATION_CRYPTO_PRIMITIVES_BC =
Collections.unmodifiableSet(EnumSet.of(BCCryptoPrimitive.KEY_ENCAPSULATION));
static final Set SIGNATURE_CRYPTO_PRIMITIVES_BC =
Collections.unmodifiableSet(EnumSet.of(BCCryptoPrimitive.SIGNATURE));
static String EMPTY_STRING = "";
static X509Certificate[] EMPTY_X509CERTIFICATES = new X509Certificate[0];
static class BCUnknownServerName extends BCSNIServerName
{
BCUnknownServerName(int nameType, byte[] encoded)
{
super(nameType, encoded);
}
}
static boolean allowLegacyMasterSecret()
{
return provTlsAllowLegacyMasterSecret;
}
static boolean allowLegacyResumption()
{
return provTlsAllowLegacyResumption;
}
static void appendCipherSuiteDetail(StringBuilder sb, ProvSSLContextSpi context, int cipherSuite)
{
// TODO Efficiency: precalculate "cipherSuiteID" and make context.getCipherSuiteName faster
sb.append("{0x"); // -DM Hex.toHexString
sb.append(Hex.toHexString(new byte[]{ (byte)(cipherSuite >> 8) }));
sb.append(",0x"); // -DM Hex.toHexString
sb.append(Hex.toHexString(new byte[]{ (byte)cipherSuite }));
sb.append('}');
String name = ProvSSLContextSpi.getCipherSuiteName(cipherSuite);
if (name == null)
{
sb.append('?');
}
else
{
sb.append('(');
sb.append(name);
sb.append(')');
}
}
static String getPeerID(String root, ProvTlsManager manager)
{
long connectionID = ProvSSLConnection.allocateConnectionID();
int transportID = manager.getTransportID();
return "[" + root + " #" + connectionID + " @" + Integer.toHexString(transportID) + "]";
}
static String getPeerReport(ProvTlsManager manager)
{
String peerHost = manager.getPeerHost();
if (peerHost == null)
{
peerHost = "(unknown)";
}
int peerPort = manager.getPeerPort();
String peerPortStr = peerPort < 0 ? "(unknown)" : Integer.toString(peerPort);
return peerHost + ":" + peerPortStr;
}
static String getSignatureAlgorithmsReport(String title, Iterable signatureSchemes)
{
StringBuilder sb = new StringBuilder(title);
sb.append(':');
if (signatureSchemes != null)
{
for (SignatureSchemeInfo signatureScheme : signatureSchemes)
{
sb.append(' ');
sb.append(signatureScheme.getJcaSignatureAlgorithmBC());
}
}
return sb.toString();
}
static void checkSessionCreationEnabled(ProvTlsManager manager)
{
if (!manager.getEnableSessionCreation())
{
throw new IllegalStateException("Cannot resume session and session creation is disabled");
}
}
static T[] clone(T[] ts)
{
return null == ts ? null : ts.clone();
}
static boolean contains(String[] values, String value)
{
for (int i = 0; i < values.length; ++i)
{
if (value.equals(values[i]))
{
return true;
}
}
return false;
}
static boolean containsNull(T[] ts)
{
for (int i = 0; i < ts.length; ++i)
{
if (null == ts[i])
{
return true;
}
}
return false;
}
static String[] copyOf(String[] data, int newLength)
{
String[] tmp = new String[newLength];
System.arraycopy(data, 0, tmp, 0, Math.min(data.length, newLength));
return tmp;
}
static TlsCredentialedDecryptor createCredentialedDecryptor(JcaTlsCrypto crypto, BCX509Key x509Key)
{
PrivateKey privateKey = x509Key.getPrivateKey();
Certificate certificate = getCertificateMessage(crypto, x509Key.getCertificateChain());
return new JceDefaultTlsCredentialedDecryptor(crypto, certificate, privateKey);
}
static TlsCredentialedSigner createCredentialedSigner(TlsContext context, JcaTlsCrypto crypto, BCX509Key x509Key,
SignatureAndHashAlgorithm sigAndHashAlg)
{
/*
* TODO[jsse] Before proceeding with EC credentials, check (TLS 1.2+) that the used curve
* was actually declared in the client's elliptic_curves/named_groups extension.
*/
TlsCryptoParameters cryptoParams = new TlsCryptoParameters(context);
PrivateKey privateKey = x509Key.getPrivateKey();
Certificate certificate = getCertificateMessage(crypto, x509Key.getCertificateChain());
return new JcaDefaultTlsCredentialedSigner(cryptoParams, crypto, privateKey, certificate, sigAndHashAlg);
}
static TlsCredentialedSigner createCredentialedSigner13(TlsContext context, JcaTlsCrypto crypto, BCX509Key x509Key,
SignatureAndHashAlgorithm sigAndHashAlg, byte[] certificateRequestContext)
{
/*
* TODO[jsse] Before proceeding with EC credentials, check (TLS 1.2+) that the used curve
* was actually declared in the client's elliptic_curves/named_groups extension.
*/
TlsCryptoParameters cryptoParams = new TlsCryptoParameters(context);
PrivateKey privateKey = x509Key.getPrivateKey();
Certificate certificate = getCertificateMessage13(crypto, x509Key.getCertificateChain(),
certificateRequestContext);
return new JcaDefaultTlsCredentialedSigner(cryptoParams, crypto, privateKey, certificate, sigAndHashAlg);
}
static boolean equals(Object a, Object b)
{
return a == b || (null != a && null != b && a.equals(b));
}
static int getMaxCertificateChainLength()
{
return provTlsMaxCertificateChainLength;
}
static int getMaxHandshakeMessageSize()
{
return provTlsMaxHandshakeMessageSize;
}
static ASN1ObjectIdentifier getNamedCurveOID(PublicKey publicKey)
{
try
{
SubjectPublicKeyInfo spki = SubjectPublicKeyInfo.getInstance(publicKey.getEncoded());
AlgorithmIdentifier algID = spki.getAlgorithm();
if (X9ObjectIdentifiers.id_ecPublicKey.equals(algID.getAlgorithm()))
{
ASN1Encodable parameters = algID.getParameters();
if (null != parameters)
{
ASN1Primitive primitive = parameters.toASN1Primitive();
if (primitive instanceof ASN1ObjectIdentifier)
{
return (ASN1ObjectIdentifier)primitive;
}
}
}
}
catch (Exception e)
{
}
return null;
}
static String[] resize(String[] data, int count)
{
if (count < data.length)
{
data = copyOf(data, count);
}
return data;
}
static String getApplicationProtocol(SecurityParameters securityParameters)
{
if (null == securityParameters || !securityParameters.isApplicationProtocolSet())
{
return null;
}
ProtocolName applicationProtocol = securityParameters.getApplicationProtocol();
if (null == applicationProtocol)
{
return "";
}
return applicationProtocol.getUtf8Decoding();
}
static String getAuthTypeServer(int keyExchangeAlgorithm)
{
/*
* For use with checkServerTrusted calls on a trust manager.
* "The key exchange algorithm portion of the cipher suites represented as a String [..]"
* according to JSSE Standard Names.
*/
switch (keyExchangeAlgorithm)
{
case KeyExchangeAlgorithm.DH_DSS:
return "DH_DSS";
case KeyExchangeAlgorithm.DH_RSA:
return "DH_RSA";
case KeyExchangeAlgorithm.DHE_DSS:
return "DHE_DSS";
case KeyExchangeAlgorithm.DHE_RSA:
return "DHE_RSA";
case KeyExchangeAlgorithm.ECDH_ECDSA:
return "ECDH_ECDSA";
case KeyExchangeAlgorithm.ECDH_RSA:
return "ECDH_RSA";
case KeyExchangeAlgorithm.ECDHE_ECDSA:
return "ECDHE_ECDSA";
case KeyExchangeAlgorithm.ECDHE_RSA:
return "ECDHE_RSA";
case KeyExchangeAlgorithm.NULL:
// For compatibility with SunJSSE, use "UNKNOWN" for TLS 1.3 cipher suites.
// return "NULL";
return "UNKNOWN";
case KeyExchangeAlgorithm.RSA:
// Prefixed to disambiguate from RSA signing credentials
return "KE:RSA";
case KeyExchangeAlgorithm.SRP_DSS:
return "SRP_DSS";
case KeyExchangeAlgorithm.SRP_RSA:
return "SRP_RSA";
default:
throw new IllegalArgumentException();
}
}
static Vector getCertificateAuthorities(BCX509ExtendedTrustManager x509TrustManager)
{
Set caSubjects = new HashSet();
for (X509Certificate acceptedIssuer : x509TrustManager.getAcceptedIssuers())
{
if (acceptedIssuer.getBasicConstraints() >= 0)
{
caSubjects.add(acceptedIssuer.getSubjectX500Principal());
}
else
{
// Trusting a non-CA certificate, so include its issuer as a CA
caSubjects.add(acceptedIssuer.getIssuerX500Principal());
}
}
if (caSubjects.isEmpty())
{
return null;
}
/*
* TODO[jsse] Destined for an extension, but what if there are too many? Extension has total
* size limit, and some servers may limit e.g. ClientHello total size.
*/
Vector certificateAuthorities = new Vector(caSubjects.size());
for (X500Principal caSubject : caSubjects)
{
certificateAuthorities.add(X500Name.getInstance(caSubject.getEncoded()));
}
return certificateAuthorities;
}
static Certificate getCertificateMessage(JcaTlsCrypto crypto, X509Certificate[] chain)
{
if (TlsUtils.isNullOrEmpty(chain))
{
throw new IllegalArgumentException();
}
TlsCertificate[] certificateList = new TlsCertificate[chain.length];
for (int i = 0; i < chain.length; ++i)
{
certificateList[i] = new JcaTlsCertificate(crypto, chain[i]);
}
return new Certificate(certificateList);
}
static Certificate getCertificateMessage13(JcaTlsCrypto crypto, X509Certificate[] chain,
byte[] certificateRequestContext)
{
if (TlsUtils.isNullOrEmpty(chain))
{
throw new IllegalArgumentException();
}
CertificateEntry[] certificateEntryList = new CertificateEntry[chain.length];
for (int i = 0; i < chain.length; ++i)
{
JcaTlsCertificate certificate = new JcaTlsCertificate(crypto, chain[i]);
// TODO[tls13] Support various extensions
Map extensions = null;
certificateEntryList[i] = new CertificateEntry(certificate, extensions);
}
return new Certificate(certificateRequestContext, certificateEntryList);
}
static X509Certificate getEndEntity(JcaTlsCrypto crypto, Certificate certificateMessage) throws IOException
{
if (certificateMessage == null || certificateMessage.isEmpty())
{
return null;
}
return getX509Certificate(crypto, certificateMessage.getCertificateAt(0));
}
static String getJcaSignatureAlgorithmBC(String jcaSignatureAlgorithm, String keyAlgorithm)
{
if (!jcaSignatureAlgorithm.endsWith("withRSAandMGF1"))
{
return jcaSignatureAlgorithm;
}
return jcaSignatureAlgorithm + ":" + keyAlgorithm;
}
static String getKeyType13(String keyAlgorithm, int namedGroup13)
{
if (namedGroup13 < 0)
{
return keyAlgorithm;
}
return keyAlgorithm + "/" + NamedGroup.getStandardName(namedGroup13);
}
static String getKeyTypeLegacyClient(short clientCertificateType)
{
switch (clientCertificateType)
{
/*
* BCJSSE doesn't support any static key exchange cipher suites; any of these values would
* be filtered out (as invalid) by the low-level TLS code.
*/
// case ClientCertificateType.dss_fixed_dh:
// return "DH_DSA";
// case ClientCertificateType.ecdsa_fixed_ecdh:
// return "EC_EC";
// case ClientCertificateType.rsa_fixed_dh:
// return "DH_RSA";
// case ClientCertificateType.rsa_fixed_ecdh:
// return "EC_RSA";
case ClientCertificateType.dss_sign:
return "DSA";
case ClientCertificateType.ecdsa_sign:
return "EC";
case ClientCertificateType.rsa_sign:
return "RSA";
default:
throw new IllegalArgumentException();
}
}
static String getKeyTypeLegacyServer(int keyExchangeAlgorithm)
{
/*
* For use with chooseServerAlias calls on a key manager. JSSE Standard Names suggest using
* the same set of key types as getKeyTypeClient, but this doesn't give enough information
* to the key manager, so we currently use the same names as getAuthTypeServer.
*/
return getAuthTypeServer(keyExchangeAlgorithm);
}
static Vector getProtocolNames(String[] applicationProtocols)
{
if (TlsUtils.isNullOrEmpty(applicationProtocols))
{
return null;
}
Vector result = new Vector(applicationProtocols.length);
for (String applicationProtocol : applicationProtocols)
{
result.add(ProtocolName.asUtf8Encoding(applicationProtocol));
}
return result;
}
static List getProtocolNames(Vector applicationProtocols)
{
if (null == applicationProtocols || applicationProtocols.isEmpty())
{
return null;
}
ArrayList result = new ArrayList(applicationProtocols.size());
for (ProtocolName applicationProtocol : applicationProtocols)
{
result.add(applicationProtocol.getUtf8Decoding());
}
return result;
}
static byte[] getStatusResponse(OCSPResponse ocspResponse) throws IOException
{
return null == ocspResponse ? TlsUtils.EMPTY_BYTES : ocspResponse.getEncoded(ASN1Encoding.DER);
}
static List getStatusResponses(CertificateStatus certificateStatus) throws IOException
{
if (null != certificateStatus)
{
switch (certificateStatus.getStatusType())
{
case CertificateStatusType.ocsp:
{
OCSPResponse ocspResponse = certificateStatus.getOCSPResponse();
return Collections.singletonList(getStatusResponse(ocspResponse));
}
case CertificateStatusType.ocsp_multi:
{
@SuppressWarnings("unchecked")
Vector ocspResponseList = certificateStatus.getOCSPResponseList();
int count = ocspResponseList.size();
ArrayList statusResponses = new ArrayList(count);
for (int i = 0; i < count; ++i)
{
OCSPResponse ocspResponse = (OCSPResponse)ocspResponseList.elementAt(i);
statusResponses.add(getStatusResponse(ocspResponse));
}
return Collections.unmodifiableList(statusResponses);
}
}
}
return null;
}
static X500Principal[] getTrustedIssuers(Vector trustedCAKeys) throws IOException
{
if (null == trustedCAKeys || trustedCAKeys.isEmpty())
{
return null;
}
int count = trustedCAKeys.size();
X500Principal[] principals = new X500Principal[count];
for (int i = 0; i < count; ++i)
{
TrustedAuthority trustedAuthority = (TrustedAuthority)trustedCAKeys.get(i);
if (IdentifierType.x509_name != trustedAuthority.getIdentifierType())
{
// TODO We currently only support the trusted_ca_keys extension if EVERY entry is an x509_name
return null;
}
principals[i] = toX500Principal(trustedAuthority.getX509Name());
}
return principals;
}
static X509Certificate getX509Certificate(JcaTlsCrypto crypto, TlsCertificate tlsCertificate) throws IOException
{
return JcaTlsCertificate.convert(crypto, tlsCertificate).getX509Certificate();
}
static X509Certificate[] getX509CertificateChain(JcaTlsCrypto crypto, Certificate certificateMessage)
{
if (certificateMessage == null || certificateMessage.isEmpty())
{
return EMPTY_X509CERTIFICATES;
}
try
{
X509Certificate[] chain = new X509Certificate[certificateMessage.getLength()];
for (int i = 0; i < chain.length; ++i)
{
chain[i] = JcaTlsCertificate.convert(crypto, certificateMessage.getCertificateAt(i)).getX509Certificate();
}
return chain;
}
catch (IOException e)
{
// TODO[jsse] Logging
throw new RuntimeException(e);
}
}
static X509Certificate[] getX509CertificateChain(java.security.cert.Certificate[] chain)
{
if (chain == null)
{
return null;
}
if (chain instanceof X509Certificate[])
{
return JsseUtils.containsNull(chain) ? null : (X509Certificate[])chain;
}
X509Certificate[] x509Chain = new X509Certificate[chain.length];
for (int i = 0; i < chain.length; ++i)
{
java.security.cert.Certificate c = chain[i];
if (!(c instanceof X509Certificate))
{
return null;
}
x509Chain[i] = (X509Certificate)c;
}
return x509Chain;
}
static X500Principal getSubject(JcaTlsCrypto crypto, Certificate certificateMessage)
{
if (certificateMessage == null || certificateMessage.isEmpty())
{
return null;
}
try
{
return getX509Certificate(crypto, certificateMessage.getCertificateAt(0)).getSubjectX500Principal();
}
catch (IOException e)
{
// TODO[jsse] Logging
throw new RuntimeException(e);
}
}
static String getAlertRaisedLogMessage(String id, short alertLevel, short alertDescription)
{
return id + " raised " + AlertLevel.getText(alertLevel) + " " + AlertDescription.getText(alertDescription) + " alert";
}
static String getAlertReceivedLogMessage(String id, short alertLevel, short alertDescription)
{
return id + " received " + AlertLevel.getText(alertLevel) + " " + AlertDescription.getText(alertDescription) + " alert";
}
static String getKeyAlgorithm(Key key)
{
if (key instanceof PrivateKey)
{
return getPrivateKeyAlgorithm((PrivateKey)key);
}
if (key instanceof PublicKey)
{
return getPublicKeyAlgorithm((PublicKey)key);
}
return key.getAlgorithm();
}
static String getPrivateKeyAlgorithm(PrivateKey privateKey)
{
String algorithm = privateKey.getAlgorithm();
/*
* TODO[fips] Early BCFIPS versions didn't return standard name for PSS keys. Once the
* minimum BCFIPS version no longer has that problem, this handler can be removed.
*/
if ("RSA".equalsIgnoreCase(algorithm))
{
// NOTE: Private keys might not support encoding (e.g. for an HSM).
byte[] encoding = privateKey.getEncoded();
if (encoding != null)
{
PrivateKeyInfo pki = PrivateKeyInfo.getInstance(encoding);
if (PKCSObjectIdentifiers.id_RSASSA_PSS.equals(pki.getPrivateKeyAlgorithm().getAlgorithm()))
{
return "RSASSA-PSS";
}
}
}
return algorithm;
}
static String getPublicKeyAlgorithm(PublicKey publicKey)
{
String algorithm = publicKey.getAlgorithm();
/*
* TODO[fips] Early BCFIPS versions didn't return standard name for PSS keys. Once the
* minimum BCFIPS version no longer has that problem, this handler can be removed.
*/
if ("RSA".equalsIgnoreCase(algorithm))
{
SubjectPublicKeyInfo spki = SubjectPublicKeyInfo.getInstance(publicKey.getEncoded());
if (PKCSObjectIdentifiers.id_RSASSA_PSS.equals(spki.getAlgorithm().getAlgorithm()))
{
return "RSASSA-PSS";
}
}
return algorithm;
}
static boolean isNameSpecified(String name)
{
return !isNullOrEmpty(name);
}
static boolean isNullOrEmpty(String s)
{
return null == s || s.length() < 1;
}
static boolean isTLSv12(String protocol)
{
ProtocolVersion protocolVersion = ProvSSLContextSpi.getProtocolVersion(protocol);
return null != protocolVersion && TlsUtils.isTLSv12(protocolVersion);
}
static boolean isTLSv13(String protocol)
{
ProtocolVersion protocolVersion = ProvSSLContextSpi.getProtocolVersion(protocol);
return null != protocolVersion && TlsUtils.isTLSv13(protocolVersion);
}
static X500Principal toX500Principal(X500Name name) throws IOException
{
return null == name ? null : new X500Principal(name.getEncoded(ASN1Encoding.DER));
}
static X500Principal[] toX500Principals(Vector names) throws IOException
{
if (null == names)
{
return null;
}
Set principals = new LinkedHashSet();
int count = names.size();
for (int i = 0; i < count; ++i)
{
X500Principal principal = toX500Principal(names.get(i));
if (null != principal)
{
principals.add(principal);
}
}
return principals.toArray(new X500Principal[0]);
}
static BCSNIServerName convertSNIServerName(ServerName serverName)
{
short nameType = serverName.getNameType();
byte[] nameData = serverName.getNameData();
switch (nameType)
{
case BCStandardConstants.SNI_HOST_NAME:
return new BCSNIHostName(nameData);
default:
return new BCUnknownServerName(nameType, nameData);
}
}
static List convertSNIServerNames(Vector serverNameList)
{
if (null == serverNameList || serverNameList.isEmpty())
{
return Collections.emptyList();
}
ArrayList result = new ArrayList(serverNameList.size());
Enumeration serverNames = serverNameList.elements();
while (serverNames.hasMoreElements())
{
result.add(convertSNIServerName(serverNames.nextElement()));
}
return Collections.unmodifiableList(result);
}
static BCSNIServerName findMatchingSNIServerName(Vector serverNameList,
Collection sniMatchers)
{
if (!serverNameList.isEmpty())
{
List sniServerNames = convertSNIServerNames(serverNameList);
for (BCSNIMatcher sniMatcher : sniMatchers)
{
if (null != sniMatcher)
{
int nameType = sniMatcher.getType();
for (BCSNIServerName sniServerName : sniServerNames)
{
if (null == sniServerName || sniServerName.getType() != nameType)
{
continue;
}
if (sniMatcher.matches(sniServerName))
{
return sniServerName;
}
break;
}
}
}
}
return null;
}
static BCSNIHostName getSNIHostName(List serverNames)
{
if (null != serverNames)
{
for (BCSNIServerName serverName : serverNames)
{
if (null != serverName && BCStandardConstants.SNI_HOST_NAME == serverName.getType())
{
if (serverName instanceof BCSNIHostName)
{
return (BCSNIHostName)serverName;
}
try
{
return new BCSNIHostName(serverName.getEncoded());
}
catch (RuntimeException e)
{
return null;
}
}
}
}
return null;
}
static String removeAllWhitespace(String s)
{
if (isNullOrEmpty(s))
{
return s;
}
int originalLength = s.length();
char[] buf = new char[originalLength];
int bufPos = 0;
for (int i = 0; i < originalLength; ++i)
{
char c = s.charAt(i);
if (!Character.isWhitespace(c))
{
buf[bufPos++] = c;
}
}
if (bufPos == 0)
{
return EMPTY_STRING;
}
if (bufPos == originalLength)
{
return s;
}
return new String(buf, 0, bufPos);
}
static boolean requireCloseNotify()
{
return provTlsRequireCloseNotify;
}
static String stripDoubleQuotes(String s)
{
return stripOuterChars(s, '"', '"');
}
static String stripSquareBrackets(String s)
{
return stripOuterChars(s, '[', ']');
}
private static String stripOuterChars(String s, char openChar, char closeChar)
{
if (s != null)
{
int sLast = s.length() - 1;
if (sLast > 0 && s.charAt(0) == openChar && s.charAt(sLast) == closeChar)
{
return s.substring(1, sLast);
}
}
return s;
}
static boolean useCompatibilityMode()
{
return provTlsUseCompatibilityMode;
}
static boolean useExtendedMasterSecret()
{
return provTlsUseExtendedMasterSecret;
}
}