/// <summary>
        /// ClientHello を待ち受け、ALPN データを取得
        /// </summary>
        /// <param name="stream"></param>
        /// <param name="protocolNames"></param>
        /// <returns></returns>
        public static bool TryGetClientAlpn(this ReadBufferedNetworkStream stream, out IReadOnlyList <string> protocolNames)
        {
            // ちゃんと Parse してから処理すれば良いんだけど、ALPN 取りたいだけなので雑……
            protocolNames = Array.Empty <string>();
            try
            {
                var         recordIndex = 0;
                var         recordData  = new List <byte>();
                ClientHello clientHello = null;

                while (recordData.Count < (clientHello != null ? clientHello.Length + 4 : int.MaxValue))
                {
                    stream.FillBuffer(recordIndex + 5);

                    var record = new TlsRecord
                    {
                        ContentType = stream[recordIndex++]
                    };
                    if (record.ContentType != 0x16)
                    {
                        return(false);    // not Handshake Record
                    }
                    record.MajorVersion = stream[recordIndex++];
                    record.MinorVersion = stream[recordIndex++];
                    record.Length       = stream.ReadBufferUInt16(recordIndex);

                    recordIndex += 2;
                    stream.FillBuffer(recordIndex + record.Length);
                    recordData.AddRange(stream.ReadBufferBytes(recordIndex, record.Length));

                    if (clientHello == null && 3 <= recordData.Count)
                    {
                        if (recordData[0] != 0x01)
                        {
                            return(false);    // not Client Hello
                        }
                        clientHello = new ClientHello
                        {
                            Length = recordData.ToUInt24(1)
                        };
                    }
                }

                clientHello.MajorVersion = recordData[4];
                clientHello.MinorVersion = recordData[5];
                if (clientHello.MajorVersion != 3 || clientHello.MinorVersion < 1)
                {
                    return(false);    // less than TLS 1.0 (SSL 3.1)
                }
                clientHello.SessionIDLength          = recordData[38];
                clientHello.CipherSuitesLength       = recordData.ToUInt16(39 + clientHello.SessionIDLength);
                clientHello.CompressionMethodsLength = recordData[41 + clientHello.SessionIDLength + clientHello.CipherSuitesLength];
                var extensionsStartIndex = 43 + clientHello.SessionIDLength + clientHello.CipherSuitesLength;
                if (clientHello.Length + 4 <= extensionsStartIndex - 2)
                {
                    return(false);    // no Extensions
                }
                clientHello.ExtensionsLength = recordData.ToUInt16(extensionsStartIndex - 2);
                var extensionsIndex = extensionsStartIndex;
                while (extensionsIndex < extensionsStartIndex + clientHello.ExtensionsLength)
                {
                    var type = recordData.ToUInt16(extensionsIndex);
                    extensionsIndex += 2;
                    var length = recordData.ToUInt16(extensionsIndex);
                    extensionsIndex += 2;
                    var data = recordData.Skip(extensionsIndex).Take(length).ToArray();
                    extensionsIndex += length;

                    if (type != 16)
                    {
                        continue;
                    }
                    var names     = new List <string>();
                    var alpnIndex = 2;  // ALPN Extension Length 何のためにあるの……
                    while (alpnIndex < length)
                    {
                        var nameLength = data[alpnIndex++];
                        var nameBytes  = new byte[nameLength];
                        Buffer.BlockCopy(data, alpnIndex, nameBytes, 0, nameLength);
                        names.Add(Encoding.ASCII.GetString(nameBytes));
                        alpnIndex += nameLength;
                    }
                    protocolNames = names.ToArray();
                    return(true);
                }
            }
            catch
            {
                return(false);
            }
            return(false);
        }
 /// <summary>
 /// 現在のバッファー内容が TLS (SSL 3.0 以降)かどうか。
 /// </summary>
 /// <param name="stream"></param>
 /// <returns></returns>
 public static bool IsTls(this ReadBufferedNetworkStream stream)
 {
     // SSL 2.0 はサポートしない
     return(0 < stream.BufferedLength &&
            stream[0] == 0x16);
 }