private static byte[] createTLSClientHello(String hostname, SslProtocols protocol) { ByteBuffer buffer = new ByteBuffer(); //build our byte array backwards buffer.Append(buildNPNExtension()); buffer.Append(buildSNIRecord(hostname)); //for now, now ALPN extension //buffer.Append(buildALPNExtension()); //prepend the length of the extensions buffer.Prepend(toInt16(buffer.Size)); //1 compression option, which is null compression buffer.PrependHex("0100"); //our ciphers buffer.PrependHex("cc14cc13cc15c02bc02f009ec00ac0140039c009c0130033009c0035002f000a00ff"); //cipher length buffer.Prepend(toInt16(34)); //SessionID len = 0 buffer.Prepend(0x00); //prepend random buffer.Prepend(buildRandomBytes()); buffer.Prepend(buildDateTimeBytes()); //TLS 1.2 marker if (protocol == SslProtocols.Tls12) { buffer.PrependHex("0303"); } else if (protocol == SslProtocols.Tls11) { buffer.PrependHex("0302"); } else if (protocol == SslProtocols.Tls) { buffer.PrependHex("0301"); } else { buffer.PrependHex("0300"); } //length so far buffer.Prepend(toInt16(buffer.Size)); //record type and 00 for the first byte of the size (stupid uint24s) buffer.PrependHex("0100"); //size again buffer.Prepend(toInt16(buffer.Size)); //outer record if (protocol == SslProtocols.Ssl3) { buffer.PrependHex(removeWhitespace("16 03 00")); } else { buffer.PrependHex(removeWhitespace("16 03 01")); } return buffer.ToByteArray(); }
/// <summary> /// Read all the bytes from a stream /// </summary> private static byte[] ReadAllBytes(Stream stream) { ByteBuffer byteBuffer = new ByteBuffer(); try { byte[] buffer = new byte[8192]; int bytesRead = 0; while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0) { //append them to our byte buffer byteBuffer.Append(buffer, bytesRead); } } catch (Exception) { byteBuffer = null; } return (byteBuffer != null) ? byteBuffer.ToByteArray() : null; }
/// <summary> /// Builds the SNI extension bytes for a hostname (SNI is the length of the hostname + 9 bytes) /// </summary> protected static byte[] buildSNIRecord(string hostname) { byte[] asciiHost = System.Text.Encoding.ASCII.GetBytes(hostname); ByteBuffer buffer = new ByteBuffer(); //0x0000 to tell that is an SNI extension buffer.AppendHex(removeWhitespace("00 00")); buffer.Append(toInt16(asciiHost.Length + 5)); buffer.Append(toInt16(asciiHost.Length + 3)); buffer.AppendHex("00"); buffer.Append(toInt16(asciiHost.Length)); buffer.Append(asciiHost); return buffer.ToByteArray(); }