[英]Access self signed X509certificates in XamarinForms for mqtt TLS connection to a Mosquitto broker
我希望使用自签名的x509证书来实现TLS安全,以使用M2MqttDotnetCore客户端连接到mosquitto mqtt代理的许多现有XamarinForms应用。
为此,我创建了一个简单的示例XamarinForms pub / sub聊天应用程序,以了解如何保护XamarinForms mqtt客户端应用程序的安全,该应用程序可以在此GitHub存储库中使用。 jhalbrecht / XamarinFormsMqttSample
我在Mosquitto_pub,python和.net控制台应用程序中有示例,这些示例实现了通过TLS和自签名证书通过端口8883成功连接到mosquitto代理的目标。 XamarinForms UWP应用程序也可以在不安全的情况下工作。 我无法让Android应用程序在端口8883上与TLS一起使用时 ,Android应用程序确实在端口1883上不安全地工作。这是Visual Studio 2017的运行时日志
[0:] M2Mqtt.Exceptions.MqttConnectionException: Exception connecting to the broker ---> System.AggregateException: One or more errors occurred. ---> System.Security.Authentication.AuthenticationException: A call to SSPI failed, see inner exception. ---> Mono.Btls.MonoBtlsException: Ssl error:1000007d:SSL routines:OPENSSL_internal:CERTIFICATE_VERIFY_FAILED
at /Users/builder/jenkins/workspace/xamarin-android-d15-9/xamarin-android/external/mono/external/boringssl/ssl/handshake_client.c:1132
at Mono.Btls.MonoBtlsContext.ProcessHandshake () [0x00038] in <fb6d78e506844b3b96d5b35aa047fbbd>:0
at Mono.Net.Security.MobileAuthenticatedStream.ProcessHandshake (Mono.Net.Security.AsyncOperationStatus status) [0x0003e] in <fb6d78e506844b3b96d5b35aa047fbbd>:0
at (wrapper remoting-invoke-with-check) Mono.Net.Security.MobileAuthenticatedStream.ProcessHandshake(Mono.Net.Security.AsyncOperationStatus)
at Mono.Net.Security.AsyncHandshakeRequest.Run (Mono.Net.Security.AsyncOperationStatus status) [0x00006] in <fb6d78e506844b3b96d5b35aa047fbbd>:0
at Mono.Net.Security.AsyncProtocolRequest+<ProcessOperation>d__24.MoveNext () [0x000ff] in <fb6d78e506844b3b96d5b35aa047fbbd>:0
--- End of stack trace from previous location where exception was thrown ---
at Mono.Net.Security.AsyncProtocolRequest+<StartOperation>d__23.MoveNext () [0x0008b] in <fb6d78e506844b3b96d5b35aa047fbbd>:0
--- End of inner exception stack trace ---
at Mono.Net.Security.MobileAuthenticatedStream+<ProcessAuthentication>d__47.MoveNext () [0x00254] in <fb6d78e506844b3b96d5b35aa047fbbd>:0
--- End of inner exception stack trace ---
at System.Threading.Tasks.Task.ThrowIfExceptional (System.Boolean includeTaskCanceledExceptions) [0x00011] in <d4a23bbd2f544c30a48c44dd622ce09f>:0
at System.Threading.Tasks.Task.Wait (System.Int32 millisecondsTimeout, System.Threading.CancellationToken cancellationToken) [0x00043] in <d4a23bbd2f544c30a48c44dd622ce09f>:0
at System.Threading.Tasks.Task.Wait () [0x00000] in <d4a23bbd2f544c30a48c44dd622ce09f>:0
at M2Mqtt.Net.MqttNetworkChannel.Connect () [0x000a8] in <72fbe921f857483bafbb8b397ec98dd1>:0
at M2Mqtt.MqttClient.Connect (System.String clientId, System.String username, System.String password, System.Boolean willRetain, System.Byte willQosLevel, System.Boolean willFlag, System.String willTopic, System.String willMessage, System.Boolean cleanSession, System.UInt16 keepAlivePeriod) [0x0001e] in <72fbe921f857483bafbb8b397ec98dd1>:0
--- End of inner exception stack trace ---
at M2Mqtt.MqttClient.Connect (System.String clientId, System.String username, System.String password, System.Boolean willRetain, System.Byte willQosLevel, System.Boolean willFlag, System.String willTopic, System.String willMessage, System.Boolean cleanSession, System.UInt16 keepAlivePeriod) [0x00037] in <72fbe921f857483bafbb8b397ec98dd1>:0
at M2Mqtt.MqttClient.Connect (System.String clientId) [0x00000] in <72fbe921f857483bafbb8b397ec98dd1>:0
at MqttDataServices.Services.MqttDataService+<Initialize>d__5.MoveNext () [0x00266] in C:\jstuff\MqttSample\MqttDataServices\Services\MqttDataService.cs:183
我当前加载和访问X509证书的方式并不安全,也不是最佳实践。 有用。 我希望最终学习如何访问每个移动平台的设备ca密钥库。 我使用跨平台插件FilePicker来加载证书,以base64对其进行编码并保存。
FileData fileData = await Plugin.FilePicker.CrossFilePicker.Current.PickFile();
if (fileData == null)
return; // user canceled file picking
string fileName = fileData.FileName;
string content = Convert.ToBase64String(fileData.DataArray, 0, fileData.DataArray.Length,
Base64FormattingOptions.None);
string deviceFileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), fileName);
File.WriteAllText(deviceFileName, content);
我已经通过Twitter与Xamarin的一些人取得了联系。 我在上述存储库中有一个未解决的问题,讨论的问题是Microsoft的@baulig相信给了我答案,但是我目前不知道如何实现它。
我只是看了证书验证代码,它的本质是
var certStore = KeyStore.GetInstance ("AndroidCAStore"); certStore.Load(null);
这是入口点: https : //github.com/mono/mono/blob/master/mcs/class/System/Mono.Btls/MonoBtlsX509LookupAndroid.cs ,它将此代码称为https://github.com/mono/ mono / blob / master / mcs / class / System / System / AndroidPlatform.cs#L101 ,然后在此处调用
xamarin-android
代码: https : //github.com/xamarin/xamarin-android/blob/master/src/Mono .Android / Android.Runtime / AndroidEnvironment.cs
KeyStore
应该是此类: https : //developer.xamarin.com/api/type/Java.Security.KeyStore/ 。因此,您应该能够通过
Java.Security.KeyStore
做到这Java.Security.KeyStore
。
初始过帐后的添加
X509Certificate caCert = X509Certificate.CreateFromCertFile(Path.Combine(filesDirectoryBasePath, "ca.crt"));
string thePfxPathOnDevice = Path.Combine(filesDirectoryBasePath, "xamarinclient.pfx");
string theBase64EncodedPfx = File.ReadAllText(thePfxPathOnDevice);
byte[] certificate = Convert.FromBase64String(theBase64EncodedPfx);
X509Certificate2 clientCert = new X509Certificate2(certificate, "xamarin");
_client = new MqttClient(
GetHostName(_xpdSetting.MqttBrokerAddress),
Int32.Parse(_xpdSetting.MqttBrokerTlsPort),
_xpdSetting.UseTls,
caCert,
clientCert,
MqttSslProtocols.TLSv1_2
//MyRemoteCertificateValidationCallback
);
由于您使用的是.Net / Mono Socket
(通过M2MqttDotnetCore),因此只需使用证书固定即可,而只需处理RemoteCertificateValidationCallback
。 因此,不会干扰Android的受信任商店等。
注意:Android上的SslStream
存在问题 ,对象分配可能会发疯……我相信(?)对此有未解决的问题。 (我不得不多次使用Java的SSLSocket来解决此问题)
├── Assets
│ └── sushihangover.cert
这是您的cert / .pem文件( 不是您的密钥! )
确保这是一个没有Unicode BOM表头的ascii文件
通过openssl示例(只需将其更改为主机和安全端口)
echo -n | openssl s_client -connect 10.1.10.250:5001 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p'
注意 :以下代码可以在NetStd2.0或Xamarin.Android中使用
X509Certificate sushihangoverCert; // Class level var
bool CertificateValidation(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors certificateErrors)
{
if (sushihangoverCert == null)
{
// There is no non-async version of OpenAppPackageFileAsync (via Xamarin.Essential) 😡 Why!!!
using (var waitHandle = new EventWaitHandle(false, EventResetMode.AutoReset))
{
Task.Run(async () =>
{
using (var assetStream = await Xamarin.Essentials.FileSystem.OpenAppPackageFileAsync("sushihangover.cert"))
using (var memStream = new MemoryStream())
{
assetStream.CopyTo(memStream);
sushihangoverCert = new X509Certificate(memStream.ToArray());
waitHandle.Set();
}
});
waitHandle.WaitOne();
}
}
return sushihangoverCert.Equals(certificate) ? true : false;
}
注意:这是使用自签名证书连接到NetCore Web API端口的
using (var tcpClient = new TcpClient("10.1.10.250", 5001))
using (var ssl = new SslStream(tcpClient.GetStream(), false, new RemoteCertificateValidationCallback(CertificateValidation)))
{
ssl.AuthenticateAsClient("10.1.10.250", null, System.Security.Authentication.SslProtocols.Tls12, false);
if (ssl.CanWrite)
{
var send = Encoding.ASCII.GetBytes("GET /api/item HTTP/1.1\r\nhost: 10.1.10.250\r\n\r\n");
await ssl.WriteAsync(send, 0, send.Length);
var buffer = new byte[4096];
var count = await ssl.ReadAsync(buffer, 0, buffer.Length);
Console.WriteLine(Encoding.UTF8.GetString(buffer, 0, count));
}
else
throw new SocketException();
}
如果您的服务器证书(是否为自签名)与您要固定的证书不匹配,您将收到:
{Mono.Btls.MonoBtlsException: Ssl error:1000007d:SSL routines:OPENSSL_internal:CERTIFICATE_VERIFY_FAILED
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.