/* * Build a ClientHello using the provided cipher suites. * Returned array contains the complete message with its * 4-byte header (but not the record header). */ byte[] MakeClientHello(int[] ccs) { /* * Assemble ClientHello. */ HList chs = new HList(0xFFFFFF); /* * Maximum protocol version. */ M.Write2(chs, maxVersion); /* * Client random. The first four bytes encode the * current time. */ byte[] clientRandom = new byte[32]; M.Enc32be((int)(M.CurrentTimeMillis() / 1000), clientRandom, 0); M.Rand(clientRandom, 4, clientRandom.Length - 4); chs.Write(clientRandom, 0, clientRandom.Length); /* * Session ID, for session resumption. */ if (sessionID == null) { M.Write1(chs, 0); } else { M.Write1(chs, sessionID.Length); chs.Write(sessionID, 0, sessionID.Length); } /* * Cipher suites. */ List <int> lcs = new List <int>(); if (ccs != null) { foreach (int s in ccs) { lcs.Add(s); } if (renegotiationSCSV) { lcs.Add(M.TLS_EMPTY_RENEGOTIATION_INFO_SCSV); } if (fallbackSCSV) { lcs.Add(M.TLS_FALLBACK_SCSV); } } M.Write2(chs, lcs.Count << 1); foreach (int s in lcs) { M.Write2(chs, s); } /* * Compression support: the NULL compression must * always be specified; optionally, Deflate compression * can be supported. */ if (deflateCompress) { M.Write1(chs, 2); M.Write1(chs, 1); M.Write1(chs, 0); } else { M.Write1(chs, 1); M.Write1(chs, 0); } /* * Extensions. */ HList exs = new HList(0xFFFF); if (serverName != null) { M.Write2(exs, M.EXT_SERVER_NAME); HList sndata = new HList(0xFFFF); HList snles = new HList(0xFFFF); snles.WriteByte(0); HList snes = new HList(0xFFFF); snes.Write(Encoding.UTF8.GetBytes(serverName)); snles.Write(snes.ToArray()); sndata.Write(snles.ToArray()); exs.Write(sndata.ToArray()); } if (renegotiationExtension) { M.Write2(exs, M.EXT_RENEGOTIATION_INFO); M.Write2(exs, 1); M.Write1(exs, 0); } if (supportedCurves != null && supportedCurves.Length > 0) { M.Write2(exs, M.EXT_SUPPORTED_CURVES); HList ecdata = new HList(0xFFFF); HList ecl = new HList(0xFFFF); foreach (int ec in supportedCurves) { M.Write2(ecl, ec); } ecdata.Write(ecl.ToArray()); exs.Write(ecdata.ToArray()); } if (exs.Length != 0) { chs.Write(exs.ToArray()); } byte[] msg = chs.ToArray(); MemoryStream ms = new MemoryStream(); ms.WriteByte(M.CLIENT_HELLO); ms.Write(msg, 0, msg.Length); return(ms.ToArray()); }
/* * Build a ClientHello using the provided cipher suites. * Returned array contains the complete message with its * 4-byte header (but not the record header). */ byte[] MakeClientHello(int[] ccs) { /* * Assemble ClientHello. */ HList chs = new HList(0xFFFFFF); /* * Maximum protocol version. */ M.Write2(chs, maxVersion); /* * Client random. The first four bytes encode the * current time. */ byte[] clientRandom = new byte[32]; M.Enc32be((int)(M.CurrentTimeMillis() / 1000), clientRandom, 0); M.Rand(clientRandom, 4, clientRandom.Length - 4); chs.Write(clientRandom, 0, clientRandom.Length); /* * Session ID, for session resumption. */ if (sessionID == null) { M.Write1(chs, 0); } else { M.Write1(chs, sessionID.Length); chs.Write(sessionID, 0, sessionID.Length); } /* * Cipher suites. */ List <int> lcs = new List <int>(); if (ccs != null) { foreach (int s in ccs) { lcs.Add(s); } if (renegotiationSCSV) { lcs.Add(M.TLS_EMPTY_RENEGOTIATION_INFO_SCSV); } if (fallbackSCSV) { lcs.Add(M.TLS_FALLBACK_SCSV); } } M.Write2(chs, lcs.Count << 1); foreach (int s in lcs) { M.Write2(chs, s); } /* * Compression support: the NULL compression must * always be specified; optionally, Deflate compression * can be supported. */ if (deflateCompress) { M.Write1(chs, 2); M.Write1(chs, 1); M.Write1(chs, 0); } else { M.Write1(chs, 1); M.Write1(chs, 0); } /* * Extensions. */ HList exs = new HList(0xFFFF); /* * With TLS 1.2, the "signature algorithms" extension is * _always_ included, even if all other extensions are * disabled. */ if (maxVersion >= M.TLSv12) { M.Write2(exs, M.EXT_SIGNATURE_ALGORITHMS); M.Write2(exs, 38); M.Write2(exs, 36); for (int s = 3; s >= 1; s--) { for (int h = 6; h >= 1; h--) { M.Write1(exs, h); M.Write1(exs, s); } } } if (serverName != null) { M.Write2(exs, M.EXT_SERVER_NAME); HList sndata = new HList(0xFFFF); HList snles = new HList(0xFFFF); snles.WriteByte(0); HList snes = new HList(0xFFFF); snes.Write(Encoding.UTF8.GetBytes(serverName)); snles.Write(snes.ToArray()); sndata.Write(snles.ToArray()); exs.Write(sndata.ToArray()); } if (renegotiationExtension) { M.Write2(exs, M.EXT_RENEGOTIATION_INFO); M.Write2(exs, 1); M.Write1(exs, 0); } if (encryptThenMACExtension) { M.Write2(exs, M.EXT_ENCRYPT_THEN_MAC); M.Write2(exs, 0); } if (supportedCurves != null && supportedCurves.Length > 0) { M.Write2(exs, M.EXT_SUPPORTED_CURVES); HList ecdata = new HList(0xFFFF); HList ecl = new HList(0xFFFF); foreach (int ec in supportedCurves) { M.Write2(ecl, ec); } ecdata.Write(ecl.ToArray()); exs.Write(ecdata.ToArray()); /* * Also send supported point format extension; it * seems to be required by some servers. */ M.Write2(exs, M.EXT_SUPPORTED_EC_POINTS); HList epdata = new HList(0xFFFF); HList epl = new HList(0xFF); M.Write1(epl, 0x00); M.Write1(epl, 0x01); M.Write1(epl, 0x02); epdata.Write(epl.ToArray()); exs.Write(epdata.ToArray()); } if (exs.Length != 0) { chs.Write(exs.ToArray()); } byte[] msg = chs.ToArray(); MemoryStream ms = new MemoryStream(); ms.WriteByte(M.CLIENT_HELLO); ms.Write(msg, 0, msg.Length); return(ms.ToArray()); }