各ターゲットフレームワーク毎のTLS1.1通信(WebRequest)

概要
-----

[WPFアプリ(.NET frameworkアプリ)でhttps(TLS1.1/TLS1.2)通信をする - nishy software (ja)](https://nishy-software.com/ja/dev-sw/wpf-app-net-https-tls/)  
こちらの記事を参考に、
「各ターゲットフレームワーク毎のTLS1.1通信(WebRequest)」
を、C#のプログラムを動かし、確かめました。  

---

確認環境
-----
### サーバサイド
* [AWS CloudFront](https://aws.amazon.com/jp/cloudfront/)
    * AWS CDN
    * コンテンツは適当に到達可能なHTMLを。
    * Security Policyに「TLSv1.1_2016」を指定
    * これで  __TLS v1.0以前では通信不可__  になります

### クライアントサイド
#### OS
Windows 10 (version: 1803)  

#### 実装
以下のような実装を用意、各ターゲットフレームワークに切り替えながらビルドします。  

```csharp
using System;
using System.IO;
using System.Net;
namespace Test
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                var url = "(CloudFrontのURL)";
                HttpWebRequest req = (System.Net.HttpWebRequest)WebRequest.Create(url);
                HttpWebResponse res = (System.Net.HttpWebResponse)req.GetResponse();
                using (var read = new StreamReader(res.GetResponseStream()))
                {
                    Console.WriteLine(read.ReadToEnd());
                }
            }
            catch(Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
            Console.ReadLine();
        }
    }
}
```

結果
-----
4.5.2以前のターゲットフレームを選択した場合、例外となりました。
この結果より、「 __デフォルト動作でTLS v1.1が扱えるのは、.NET Framework 4.6以降__ 」であることが確認できました。 
3.5では例外の内容が変化してますね。   

ターゲットフレームワーク|結果|備考
---|---|---
4.7.2|〇|
4.7.1|〇|
4.7|〇|
4.6|〇|
4.5.2|×|System.Net.WebException: 要求は中止されました: SSL/TLS のセキュリティで保護されているチャネルを作成できませんでした
4.5|×|System.Net.WebException: 要求は中止されました: SSL/TLS のセキュリティで保護されているチャネルを作成できませんでした
4|×|System.Net.WebException: 要求は中止されました: SSL/TLS のセキュリティで保護されているチャネルを作成できませんでした
3.5|×|System.Net.WebException: 基礎になる接続が閉じられました: 送信時に、予期しないエラーが発生しました。 ---> System.IO.IOException: トランスポート ストリームから予期しない EOF または 0 バイトを受信しました。

### 例外内容(ターゲットフレームワーク: .NET Framework 4.5.2)
```
System.Net.WebException: 要求は中止されました: SSL/TLS のセキュリティで保護されているチャネルを作成できませんでした
   場所 System.Net.HttpWebRequest.GetResponse()
   場所 TlsTrial.Program.Main(String[] args) 場所 C:\Users\uchiyama.masahiko\source\repos\TlsTrial\TlsTrial452\Program.cs:行 15
```

### 例外内容(ターゲットフレームワーク: .NET Framework 3.5)
```
System.Net.WebException: 基礎になる接続が閉じられました: 送信時に、予期しないエラーが発生しました。 ---> System.IO.IOException: トランスポート ストリームから予期しない EOF または 0 バイトを受信しました。
   場所 System.Net.FixedSizeReader.ReadPacket(Byte[] buffer, Int32 offset, Int32 count)
   場所 System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
   場所 System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
   場所 System.Net.Security.SslState.ForceAuthentication(Boolean receiveFirst, Byte[] buffer, AsyncProtocolRequest asyncRequest)
   場所 System.Net.Security.SslState.ProcessAuthentication(LazyAsyncResult lazyResult)
   場所 System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   場所 System.Net.TlsStream.ProcessAuthentication(LazyAsyncResult result)
   場所 System.Net.TlsStream.Write(Byte[] buffer, Int32 offset, Int32 size)
   場所 System.Net.PooledStream.Write(Byte[] buffer, Int32 offset, Int32 size)
   場所 System.Net.ConnectStream.WriteHeaders(Boolean async)
   --- 内部例外スタック トレースの終わり ---
   場所 System.Net.HttpWebRequest.GetResponse()
   場所 TlsTrial.Program.Main(String[] args) 場所 C:\Users\uchiyama.masahiko\source\repos\TlsTrial\TlsTrial472\Program.cs:行 15
```

おまけ
-----
### 実装拡張すれば、.NET Framework 4.0でもTLS v1.1での通信が可能だった
必要なKBが当たっていることが前提。
詳細は概要で示した記事を御参照下さい。

```csharp
using System;
using System.IO;
using System.Net;
namespace Test
{
    public static class SecurityProtocolTypeExtensions
    {
      public const SecurityProtocolType Tls12 = (SecurityProtocolType)0x00000C00;
      public const SecurityProtocolType Tls11 = (SecurityProtocolType)0x00000300;
      public const SecurityProtocolType SystemDefault = (SecurityProtocolType)0;
    }

    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls
                    | SecurityProtocolTypeExtensions.Tls11 | SecurityProtocolTypeExtensions.Tls12;
            }
            catch
            {
                ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3
                    | SecurityProtocolType.Tls;
            }

            try
            {
                var url = "(CloudFrontのURL)";
                HttpWebRequest req = (System.Net.HttpWebRequest)WebRequest.Create(url);
                HttpWebResponse res = (System.Net.HttpWebResponse)req.GetResponse();
                using (var read = new StreamReader(res.GetResponseStream()))
                {
                    Console.WriteLine(read.ReadToEnd());
                }
            }
            catch(Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
            Console.ReadLine();
        }
    }
}
```

### 関連リンク
* [TLS 1.2 を有効にする方法 - Configuration Manager | Microsoft Docs](https://docs.microsoft.com/ja-jp/sccm/core/plan-design/security/enable-tls-1-2)
* [.NET Framework で TLS1.1 および 1.2 を有効化する方法 ? Japan IE Support Team Blog](https://blogs.technet.microsoft.com/jpieblog/2015/04/07/net-framework-tls1-1-1-2/)
* [.NET Framework でのトランスポート層セキュリティ (TLS) のベスト プラクティス | Microsoft Docs](https://docs.microsoft.com/ja-jp/dotnet/framework/network-programming/tls)

---