using System; using System.Collections.Generic; using System.IO; using Org.BouncyCastle.Utilities; using Org.BouncyCastle.Utilities.IO; namespace Org.BouncyCastle.Tls { public sealed class ServerNameList { private readonly IList m_serverNameList; /// an of . public ServerNameList(IList serverNameList) { if (null == serverNameList) throw new ArgumentNullException("serverNameList"); this.m_serverNameList = serverNameList; } /// an of . public IList ServerNames { get { return m_serverNameList; } } /// Encode this to a . /// the to encode to . /// public void Encode(Stream output) { MemoryStream buf = new MemoryStream(); short[] nameTypesSeen = TlsUtilities.EmptyShorts; foreach (ServerName entry in ServerNames) { nameTypesSeen = CheckNameType(nameTypesSeen, entry.NameType); if (null == nameTypesSeen) throw new TlsFatalAlert(AlertDescription.internal_error); entry.Encode(buf); } int length = Convert.ToInt32(buf.Length); TlsUtilities.CheckUint16(length); TlsUtilities.WriteUint16(length, output); buf.WriteTo(output); } /// Parse a from a . /// the to parse from. /// a object. /// public static ServerNameList Parse(Stream input) { byte[] data = TlsUtilities.ReadOpaque16(input, 1); MemoryStream buf = new MemoryStream(data, false); short[] nameTypesSeen = TlsUtilities.EmptyShorts; var server_name_list = new List(); while (buf.Position < buf.Length) { ServerName entry = ServerName.Parse(buf); nameTypesSeen = CheckNameType(nameTypesSeen, entry.NameType); if (null == nameTypesSeen) throw new TlsFatalAlert(AlertDescription.illegal_parameter); server_name_list.Add(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 NameType. if (Arrays.Contains(nameTypesSeen, nameType)) return null; return Arrays.Append(nameTypesSeen, nameType); } } }