package org.bouncycastle.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); } }