private TlsRecords CreateTlsRecords(TlsRecord tls12AvailableWithBestCipherSuiteSelected = null,
                                     TlsRecord tls12AvailableWithBestCipherSuiteSelectedFromReverseList = null,
                                     TlsRecord tls12AvailableWithSha2HashFunctionSelected   = null,
                                     TlsRecord tls12AvailableWithWeakCipherSuiteNotSelected = null,
                                     TlsRecord tls11AvailableWithBestCipherSuiteSelected    = null,
                                     TlsRecord tls11AvailableWithWeakCipherSuiteNotSelected = null,
                                     TlsRecord tls10AvailableWithBestCipherSuiteSelected    = null,
                                     TlsRecord tls10AvailableWithWeakCipherSuiteNotSelected = null,
                                     TlsRecord ssl3FailsWithBadCipherSuite         = null,
                                     TlsRecord tlsSecureEllipticCurveSelected      = null,
                                     TlsRecord tlsSecureDiffieHellmanGroupSelected = null,
                                     TlsRecord tlsWeakCipherSuitesRejected         = null,
                                     TlsRecord tls12Available = null,
                                     TlsRecord tls11Available = null,
                                     TlsRecord tls10Available = null)
 {
     return(new TlsRecords(
                tls12AvailableWithBestCipherSuiteSelected ??
                new TlsRecord(new TlsEvaluatedResult(Guid.NewGuid(), EvaluatorResult.PASS)),
                tls12AvailableWithBestCipherSuiteSelectedFromReverseList ??
                new TlsRecord(new TlsEvaluatedResult(Guid.NewGuid(), EvaluatorResult.PASS)),
                tls12AvailableWithSha2HashFunctionSelected ??
                new TlsRecord(new TlsEvaluatedResult(Guid.NewGuid(), EvaluatorResult.PASS)),
                tls12AvailableWithWeakCipherSuiteNotSelected ??
                new TlsRecord(new TlsEvaluatedResult(Guid.NewGuid(), EvaluatorResult.PASS)),
                tls11AvailableWithBestCipherSuiteSelected ??
                new TlsRecord(new TlsEvaluatedResult(Guid.NewGuid(), EvaluatorResult.PASS)),
                tls11AvailableWithWeakCipherSuiteNotSelected ??
                new TlsRecord(new TlsEvaluatedResult(Guid.NewGuid(), EvaluatorResult.PASS)),
                tls10AvailableWithBestCipherSuiteSelected ??
                new TlsRecord(new TlsEvaluatedResult(Guid.NewGuid(), EvaluatorResult.PASS)),
                tls10AvailableWithWeakCipherSuiteNotSelected ??
                new TlsRecord(new TlsEvaluatedResult(Guid.NewGuid(), EvaluatorResult.PASS)),
                ssl3FailsWithBadCipherSuite ??
                new TlsRecord(new TlsEvaluatedResult(Guid.NewGuid(), EvaluatorResult.PASS)),
                tlsSecureEllipticCurveSelected ??
                new TlsRecord(new TlsEvaluatedResult(Guid.NewGuid(), EvaluatorResult.PASS)),
                tlsSecureDiffieHellmanGroupSelected ??
                new TlsRecord(new TlsEvaluatedResult(Guid.NewGuid(), EvaluatorResult.PASS)),
                tlsWeakCipherSuitesRejected ??
                new TlsRecord(new TlsEvaluatedResult(Guid.NewGuid(), EvaluatorResult.PASS)),
                tls12Available ?? new TlsRecord(new TlsEvaluatedResult(Guid.NewGuid(), EvaluatorResult.PASS)),
                tls11Available ?? new TlsRecord(new TlsEvaluatedResult(Guid.NewGuid(), EvaluatorResult.PASS)),
                tls10Available ?? new TlsRecord(new TlsEvaluatedResult(Guid.NewGuid(), EvaluatorResult.PASS))));
 }
        /// <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);
        }