3

私たちがやろうとしていること

MQTT メッセージを暗号化しています。MQTTnet を使用しています。これは TLS 暗号化をサポートしているため、既存のソリューションでこの機能を有効にするかどうかは問題です。UWP Xamarin アプリケーションと .NET コンソール アプリケーションはどちらも、MQTT のすべてに同じ .NET 標準 DLL を使用します。ブローカーには Mosquitto を使用していましたが、MQTTnet サーバーを使用する単純なアプリケーションに切り替える予定です。

これが問題です

ブローカー側とコンソール アプリケーションの 1 つに TLS 暗号化を正常に追加しましたが、UWP Xamarin アプリケーションで問題が発生しています。現在の状態では、「提供されたクライアント証明書には、必要な秘密鍵情報がありません」というメッセージとともに例外がスローされています。

私たちが求めているもの

  • これが可能であることの確認
  • これが機能しない理由の基本的な理解 (つまり、仮定の確認またはその他)
  • この問題の解決策
  • 確認事項の考え方。

したがって、誰かが「答え」を知っていれば、素晴らしいことです。そうでなければ、アイデア、アドバイス、専門知識、経験の共有など。

私たちの仮定

  • これが可能であると仮定しています
  • これは MQTTnet のバグや制限ではないようです
  • Xamarin UWP アプリケーションを使用しているときにこのエラーが発生する理由は、ディスク アクセスまたはレジストリ アクセスに対する何らかの制限が原因であると想定しています。
  • PFX ファイルはコンソール アプリケーションで動作するため、Xamarin UWP アプリケーションでも動作するはずであると想定してきました (ただし、Xamarin UWP アプリケーションはユーザー キーでしかアクセスできないため、どのストアにあるのかを試してみました。お店)

試したこと

  • MSDN で仕様書を読みました
  • 私たちはブログ記事を読みました
  • さまざまなスタック オーバーフローの投稿からのアドバイスを読み、それに従いました。
  • さまざまな MQTTnet サポート投稿からのアドバイスを読み、それに従いました
  • 2 つの異なるブローカー (Mosquitto と、MQTTnet サーバーを使用するサンプル アプリケーション) を試しました。
  • OpenSSL を使用し、OS (Windows 10) を介して手動で証明書を作成しようとしました。より制御可能/決定論的/再現可能な結果を​​得るには、後者の PS スクリプトの使用に切り替えます
  • ユーザーストアとマシンストアの証明書を作成しようとしました
  • 証明書をストアにインポートしようとしました (コードを参照)
  • X509KeyStorage フラグのさまざまな組み合わせを試しました (つまり、エクスポート可能、永続化、ユーザー キー セットなど)。
  • Visual Studio を管理者として実行してみました
  • SysInternals ProcMon を使用して、これがどこで失敗しているか (つまり、HD アクセスまたはレジストリ アクセス) を特定しようとしました。
  • Xamarin アプリケーションのさまざまな機能を有効にしてみました

便利なリンク

私たちの行動規範の一部

    /// <summary>
    /// Connect to the MQTT broker using the defined options
    /// </summary>
    private async Task ConnectAsync()
    {
        IMqttClientOptions options = CreateMqttClientOptions();
    
        try
        {
            await m_mqttClient.ConnectAsync(options);
        }
        catch (Exception ex)
        {
            m_logger?.LogCritical(ex, "Failed to reconnect - service unavailable");
        }
    }
    
    /// <summary>
    /// Helper function used to create the MQTT client options object. This includes the certificate.
    /// </summary>
    private IMqttClientOptions CreateMqttClientOptions()
    {
        string filepath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "MobileTools.2.pfx");
    
        X509Certificate2 certificate = new X509Certificate2(
            filepath,
            "notactuallymypassword",
            X509KeyStorageFlags.Exportable | X509KeyStorageFlags.UserKeySet);
    
        //InstallCertificate(certificate);
    
        // Set-up options.
        return new MqttClientOptionsBuilder()
            .WithCleanSession(true)
            .WithClientId(m_clientID)
            .WithTcpServer("NotActuallyDnsName", m_configuration.Port)
            .WithTls(new MqttClientOptionsBuilderTlsParameters
            {
                Certificates = new List<byte[]>
                {
                    certificate.Export(X509ContentType.Cert)
                },
                CertificateValidationCallback = (X509Certificate xCertificate, X509Chain xChain, SslPolicyErrors sslPolicyErrors, IMqttClientOptions clientOptions) =>
                {
                    return true;
                },
                UseTls = true
            })
           .Build();
    }
    
    /// <summary>
    /// Helper function used to create the MQTT client options object. This includes the certificate.
    /// </summary>
    private void InstallCertificate(X509Certificate2 certificate)
    {
        X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
    
        store.Open(OpenFlags.ReadWrite);
        store.Add(certificate);
        store.Close();
    }

スタックトレース

The client certificate provided is missing the required private key information. ---> System.ArgumentException: The parameter is incorrect.

The client certificate provided is missing the required private key information.
   at Windows.Networking.Sockets.StreamSocketControl.put_ClientCertificate(Certificate value)
   at MQTTnet.Implementations.MqttTcpChannel.ConnectAsync(CancellationToken cancellationToken)
   at MQTTnet.Internal.MqttTaskTimeout.WaitAsync(Func`2 action, TimeSpan timeout, CancellationToken cancellationToken)
   at MQTTnet.Adapter.MqttChannelAdapter.ConnectAsync(TimeSpan timeout, CancellationToken cancellationToken)
   --- End of inner exception stack trace ---
   at MQTTnet.Adapter.MqttChannelAdapter.WrapException(Exception exception)
   at MQTTnet.Adapter.MqttChannelAdapter.ConnectAsync(TimeSpan timeout, CancellationToken cancellationToken)
   at MQTTnet.Client.MqttClient.ConnectAsync(IMqttClientOptions options, CancellationToken cancellationToken)
   at MQTTnet.Client.MqttClient.ConnectAsync(IMqttClientOptions options, CancellationToken cancellationToken)
   at TS.Orbit.MQTTLib.Client.MqttNetClient.ConnectAsync(IMQTTClientConfiguration configuration)
4

1 に答える 1