blob: 7e0e3a9adab866565635053b10e410b2e3b0420e [file] [log] [blame]
package org.bouncycastle.crypto.tls;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Vector;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.io.Streams;
public class ServerNameList
{
protected Vector serverNameList;
/**
* @param serverNameList a {@link Vector} of {@link ServerName}.
*/
public ServerNameList(Vector serverNameList)
{
if (serverNameList == null)
{
throw new IllegalArgumentException("'serverNameList' must not be null");
}
this.serverNameList = serverNameList;
}
/**
* @return a {@link Vector} of {@link ServerName}.
*/
public Vector getServerNameList()
{
return serverNameList;
}
/**
* Encode this {@link ServerNameList} to an {@link OutputStream}.
*
* @param output
* the {@link OutputStream} to encode to.
* @throws IOException
*/
public void encode(OutputStream output) throws IOException
{
ByteArrayOutputStream buf = new ByteArrayOutputStream();
short[] nameTypesSeen = new short[0];
for (int i = 0; i < serverNameList.size(); ++i)
{
ServerName entry = (ServerName)serverNameList.elementAt(i);
nameTypesSeen = checkNameType(nameTypesSeen, entry.getNameType());
if (nameTypesSeen == null)
{
throw new TlsFatalAlert(AlertDescription.internal_error);
}
entry.encode(buf);
}
TlsUtils.checkUint16(buf.size());
TlsUtils.writeUint16(buf.size(), output);
Streams.writeBufTo(buf, output);
}
/**
* Parse a {@link ServerNameList} from an {@link InputStream}.
*
* @param input
* the {@link InputStream} to parse from.
* @return a {@link ServerNameList} object.
* @throws IOException
*/
public static ServerNameList parse(InputStream input) throws IOException
{
int length = TlsUtils.readUint16(input);
if (length < 1)
{
throw new TlsFatalAlert(AlertDescription.decode_error);
}
byte[] data = TlsUtils.readFully(length, input);
ByteArrayInputStream buf = new ByteArrayInputStream(data);
short[] nameTypesSeen = new short[0];
Vector server_name_list = new Vector();
while (buf.available() > 0)
{
ServerName entry = ServerName.parse(buf);
nameTypesSeen = checkNameType(nameTypesSeen, entry.getNameType());
if (nameTypesSeen == null)
{
throw new TlsFatalAlert(AlertDescription.illegal_parameter);
}
server_name_list.addElement(entry);
}
return new ServerNameList(server_name_list);
}
private static short[] checkNameType(short[] nameTypesSeen, short nameType)
{
/*
* RFC 6066 3. The ServerNameList MUST NOT contain more than one name of the same
* name_type.
*/
if (!NameType.isValid(nameType) || Arrays.contains(nameTypesSeen, nameType))
{
return null;
}
return Arrays.append(nameTypesSeen, nameType);
}
}