ASP.NET CoreでSSL/TSL自己証明書をMacに組み込む方法


ASP.NET Core WebAPI で SSL/TLSの自己証明書をMacに組み込む方法をご紹介します。

なお、ASP.NET Core MVC でも違いはないので心配ないです。

これを行っていないと、ASP.NET Core WebAPI プロジェクト実行時、いきなり以下のエラーが発生して実行できないという問題が起きます。これはなかなかつらいです。

fail: Microsoft.AspNetCore.Server.Kestrel[0]
      Uncaught exception from the OnConnectionAsync method of an IConnectionAdapter.
System.Security.Authentication.AuthenticationException: Authentication failed, see inner exception. ---> Interop+AppleCrypto+SslException: Internal error
   --- End of inner exception stack trace ---
   at System.Net.Security.SslState.StartSendAuthResetSignal(ProtocolToken message, AsyncProtocolRequest asyncRequest, ExceptionDispatchInfo exception)
   at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.ForceAuthentication(Boolean receiveFirst, Byte[] buffer, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.ProcessAuthentication(LazyAsyncResult lazyResult)
   at System.Net.Security.SslStream.BeginAuthenticateAsServer(SslServerAuthenticationOptions sslServerAuthenticationOptions, CancellationToken cancellationToken, AsyncCallback asyncCallback, Object asyncState)
   at System.Net.Security.SslStream.<>c.<AuthenticateAsServerAsync>b__51_0(SslServerAuthenticationOptions arg1, CancellationToken arg2, AsyncCallback callback, Object state)
   at System.Threading.Tasks.TaskFactory`1.FromAsyncImpl[TArg1,TArg2](Func`5 beginMethod, Func`2 endFunction, Action`1 endAction, TArg1 arg1, TArg2 arg2, Object state, TaskCreationOptions creationOptions)
   at System.Threading.Tasks.TaskFactory.FromAsync[TArg1,TArg2](Func`5 beginMethod, Action`1 endMethod, TArg1 arg1, TArg2 arg2, Object state, TaskCreationOptions creationOptions)
   at System.Threading.Tasks.TaskFactory.FromAsync[TArg1,TArg2](Func`5 beginMethod, Action`1 endMethod, TArg1 arg1, TArg2 arg2, Object state)
   at System.Net.Security.SslStream.AuthenticateAsServerAsync(SslServerAuthenticationOptions sslServerAuthenticationOptions, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Server.Kestrel.Https.Internal.HttpsConnectionAdapter.InnerOnConnectionAsync(ConnectionAdapterContext context)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.HttpConnection.ApplyConnectionAdaptersAsync()

この問題を解決するには、Mac に SSL/TLS 自己証明書を組み込む必要があります。

これには以下の手順で証明書を作成していきます。

$ openssl genrsa -out key.pem 2048
$ openssl req -new -sha256 -key key.pem -out csr.csr

以下のように設定します。Common Name に localhost、password に password を指定しています。

Country Name (2 letter code) []:
State or Province Name (full name) []:
Locality Name (eg, city) []:
Organization Name (eg, company) []:
Organizational Unit Name (eg, section) []:
Common Name (eg, fully qualified host name) []:localhost
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:password

さらに以下のコマンドを実行します。

$ openssl req -x509 -sha256 -days 365 -key key.pem -in csr.csr -out certificate.pem
$ openssl pkcs12 -export -out localhost.pfx -inkey key.pem -in certificate.pem

次に、Visual Studio Code のプロジェクトで、Kestrel Https Extension Package をインストールします。

$ dotnet add package Microsoft.AspNetCore.Server.Kestrel.Https
$ dotnet restore

しかし、以下のようにエラーが表示されてしまう場合があります。

/Users/xxxxx/Projects/myapi/myapi.csproj : warning NU1608: 依存関係の制約外で検出されたパッケージのバージョン: Microsoft.AspNetCore.App 2.1.0 では Microsoft.AspNetCore.Server.Kestrel.Https (= 2.1.0) が必要ですが、バージョン Microsoft.AspNetCore.Server.Kestrel.Https 2.1.3 は解決されました。
/Users/xxxxx/Projects/myapi/myapi.csproj : error NU1107: Microsoft.AspNetCore.Connections.Abstractions でバージョンの競合が検出されました。この問題を解決するには、プロジェクトから直接パッケージを参照してください。
/Users/xxxxx/Projects/myapi/myapi.csproj : error NU1107:  myapi -> Microsoft.AspNetCore.Server.Kestrel.Https2.1.3 -> Microsoft.AspNetCore.Server.Kestrel.Core 2.1.3 -> Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions 2.1.3 -> Microsoft.AspNetCore.Connections.Abstractions (>= 2.1.3)
/Users/xxxxx/Projects/myapi/myapi.csproj : error NU1107:  myapi -> Microsoft.AspNetCore.App 2.1.0 -> Microsoft.AspNetCore.Connections.Abstractions (= 2.1.0).

エラーメッセージを確認し、.csproj の Kestrel Https Extension Package のバージョンを 2.1.0 にして再度、dotnet resoteを実行するとエラーが表示されなくなります。

<ItemGroup>
 <PackageReference Include="Microsoft.AspNetCore.App" />
 <PackageReference Include="Microsoft.AspNetCore.Server.Kestrel.Https" Version="2.1.0" />
</ItemGroup>

最後に Program.cs を以下のように SSL/TLS 証明書を読み込むように設定します。

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Microsoft.AspNetCore.Server.Kestrel.Https;
using System.Net;
namespace myapi
{
    public class Program
    {
        public static void Main(string[] args)
        {
            CreateWebHostBuilder(args).Build().Run();
        }

        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseKestrel(options => {
                        options.Listen(IPAddress.Loopback,5001, ListenOptions => {
                            ListenOptions.UseHttps("localhost.pfx","password");
                        });
                    }
                )
                .UseStartup<Startup>();
    }
}

これで WebAPI を HTTPS で表示できるようになりました。

f:id:fnyablog:20180908092820p:plain

・参考サイト