package org.bouncycastle.crypto.tls;
import java.io.IOException;
import java.util.Hashtable;
import java.util.Vector;
import org.bouncycastle.util.Arrays;
public abstract class AbstractTlsServer
extends AbstractTlsPeer
implements TlsServer
{
protected TlsCipherFactory cipherFactory;
protected TlsServerContext context;
protected ProtocolVersion clientVersion;
protected int[] offeredCipherSuites;
protected short[] offeredCompressionMethods;
protected Hashtable clientExtensions;
protected boolean encryptThenMACOffered;
protected short maxFragmentLengthOffered;
protected boolean truncatedHMacOffered;
protected Vector supportedSignatureAlgorithms;
protected boolean eccCipherSuitesOffered;
protected int[] namedCurves;
protected short[] clientECPointFormats, serverECPointFormats;
protected ProtocolVersion serverVersion;
protected int selectedCipherSuite;
protected short selectedCompressionMethod;
protected Hashtable serverExtensions;
public AbstractTlsServer()
{
this(new DefaultTlsCipherFactory());
}
public AbstractTlsServer(TlsCipherFactory cipherFactory)
{
this.cipherFactory = cipherFactory;
}
protected boolean allowEncryptThenMAC()
{
return true;
}
protected boolean allowTruncatedHMac()
{
return false;
}
protected Hashtable checkServerExtensions()
{
return this.serverExtensions = TlsExtensionsUtils.ensureExtensionsInitialised(this.serverExtensions);
}
protected abstract int[] getCipherSuites();
protected short[] getCompressionMethods()
{
return new short[]{CompressionMethod._null};
}
protected ProtocolVersion getMaximumVersion()
{
return ProtocolVersion.TLSv11;
}
protected ProtocolVersion getMinimumVersion()
{
return ProtocolVersion.TLSv10;
}
protected boolean supportsClientECCCapabilities(int[] namedCurves, short[] ecPointFormats)
{
if (namedCurves == null)
{
return TlsECCUtils.hasAnySupportedNamedCurves();
}
for (int i = 0; i < namedCurves.length; ++i)
{
int namedCurve = namedCurves[i];
if (NamedCurve.isValid(namedCurve)
&& (!NamedCurve.refersToASpecificNamedCurve(namedCurve) || TlsECCUtils.isSupportedNamedCurve(namedCurve)))
{
return true;
}
}
return false;
}
public void init(TlsServerContext context)
{
this.context = context;
}
public void notifyClientVersion(ProtocolVersion clientVersion)
throws IOException
{
this.clientVersion = clientVersion;
}
public void notifyFallback(boolean isFallback) throws IOException
{
if (isFallback && getMaximumVersion().isLaterVersionOf(clientVersion))
{
throw new TlsFatalAlert(AlertDescription.inappropriate_fallback);
}
}
public void notifyOfferedCipherSuites(int[] offeredCipherSuites)
throws IOException
{
this.offeredCipherSuites = offeredCipherSuites;
this.eccCipherSuitesOffered = TlsECCUtils.containsECCCipherSuites(this.offeredCipherSuites);
}
public void notifyOfferedCompressionMethods(short[] offeredCompressionMethods)
throws IOException
{
this.offeredCompressionMethods = offeredCompressionMethods;
}
public void processClientExtensions(Hashtable clientExtensions)
throws IOException
{
this.clientExtensions = clientExtensions;
if (clientExtensions != null)
{
this.encryptThenMACOffered = TlsExtensionsUtils.hasEncryptThenMACExtension(clientExtensions);
this.maxFragmentLengthOffered = TlsExtensionsUtils.getMaxFragmentLengthExtension(clientExtensions);
if (maxFragmentLengthOffered >= 0 && !MaxFragmentLength.isValid(maxFragmentLengthOffered))
{
throw new TlsFatalAlert(AlertDescription.illegal_parameter);
}
this.truncatedHMacOffered = TlsExtensionsUtils.hasTruncatedHMacExtension(clientExtensions);
this.supportedSignatureAlgorithms = TlsUtils.getSignatureAlgorithmsExtension(clientExtensions);
if (this.supportedSignatureAlgorithms != null)
{
if (!TlsUtils.isSignatureAlgorithmsExtensionAllowed(clientVersion))
{
throw new TlsFatalAlert(AlertDescription.illegal_parameter);
}
}
this.namedCurves = TlsECCUtils.getSupportedEllipticCurvesExtension(clientExtensions);
this.clientECPointFormats = TlsECCUtils.getSupportedPointFormatsExtension(clientExtensions);
}
}
public ProtocolVersion getServerVersion()
throws IOException
{
if (getMinimumVersion().isEqualOrEarlierVersionOf(clientVersion))
{
ProtocolVersion maximumVersion = getMaximumVersion();
if (clientVersion.isEqualOrEarlierVersionOf(maximumVersion))
{
return serverVersion = clientVersion;
}
if (clientVersion.isLaterVersionOf(maximumVersion))
{
return serverVersion = maximumVersion;
}
}
throw new TlsFatalAlert(AlertDescription.protocol_version);
}
public int getSelectedCipherSuite()
throws IOException
{
Vector sigAlgs = TlsUtils.getUsableSignatureAlgorithms(supportedSignatureAlgorithms);
boolean eccCipherSuitesEnabled = supportsClientECCCapabilities(this.namedCurves, this.clientECPointFormats);
int[] cipherSuites = getCipherSuites();
for (int i = 0; i < cipherSuites.length; ++i)
{
int cipherSuite = cipherSuites[i];
if (Arrays.contains(this.offeredCipherSuites, cipherSuite)
&& (eccCipherSuitesEnabled || !TlsECCUtils.isECCCipherSuite(cipherSuite))
&& TlsUtils.isValidCipherSuiteForVersion(cipherSuite, serverVersion)
&& TlsUtils.isValidCipherSuiteForSignatureAlgorithms(cipherSuite, sigAlgs))
{
return this.selectedCipherSuite = cipherSuite;
}
}
throw new TlsFatalAlert(AlertDescription.handshake_failure);
}
public short getSelectedCompressionMethod()
throws IOException
{
short[] compressionMethods = getCompressionMethods();
for (int i = 0; i < compressionMethods.length; ++i)
{
if (Arrays.contains(offeredCompressionMethods, compressionMethods[i]))
{
return this.selectedCompressionMethod = compressionMethods[i];
}
}
throw new TlsFatalAlert(AlertDescription.handshake_failure);
}
public Hashtable getServerExtensions()
throws IOException
{
if (this.encryptThenMACOffered && allowEncryptThenMAC())
{
if (TlsUtils.isBlockCipherSuite(this.selectedCipherSuite))
{
TlsExtensionsUtils.addEncryptThenMACExtension(checkServerExtensions());
}
}
if (this.maxFragmentLengthOffered >= 0 && MaxFragmentLength.isValid(maxFragmentLengthOffered))
{
TlsExtensionsUtils.addMaxFragmentLengthExtension(checkServerExtensions(), this.maxFragmentLengthOffered);
}
if (this.truncatedHMacOffered && allowTruncatedHMac())
{
TlsExtensionsUtils.addTruncatedHMacExtension(checkServerExtensions());
}
if (this.clientECPointFormats != null && TlsECCUtils.isECCCipherSuite(this.selectedCipherSuite))
{
this.serverECPointFormats = new short[]{ ECPointFormat.uncompressed,
ECPointFormat.ansiX962_compressed_prime, ECPointFormat.ansiX962_compressed_char2, };
TlsECCUtils.addSupportedPointFormatsExtension(checkServerExtensions(), serverECPointFormats);
}
return serverExtensions;
}
public Vector getServerSupplementalData()
throws IOException
{
return null;
}
public CertificateStatus getCertificateStatus()
throws IOException
{
return null;
}
public CertificateRequest getCertificateRequest()
throws IOException
{
return null;
}
public void processClientSupplementalData(Vector clientSupplementalData)
throws IOException
{
if (clientSupplementalData != null)
{
throw new TlsFatalAlert(AlertDescription.unexpected_message);
}
}
public void notifyClientCertificate(Certificate clientCertificate)
throws IOException
{
throw new TlsFatalAlert(AlertDescription.internal_error);
}
public TlsCompression getCompression()
throws IOException
{
switch (selectedCompressionMethod)
{
case CompressionMethod._null:
return new TlsNullCompression();
default:
throw new TlsFatalAlert(AlertDescription.internal_error);
}
}
public TlsCipher getCipher()
throws IOException
{
int encryptionAlgorithm = TlsUtils.getEncryptionAlgorithm(selectedCipherSuite);
int macAlgorithm = TlsUtils.getMACAlgorithm(selectedCipherSuite);
return cipherFactory.createCipher(context, encryptionAlgorithm, macAlgorithm);
}
public NewSessionTicket getNewSessionTicket()
throws IOException
{
return new NewSessionTicket(0L, TlsUtils.EMPTY_BYTES);
}
}