Get WebException on compatible S3 storage - vb.net

I develop an application that connects with a compatible S3 server located in an internal network. For that reason, the server where this app is going to run does not have internet connectivity.
I am using the amazon web service sdk (AWSSDK.S3) to connect with the server and it provides all the necessary functionality.
When I try to connect with the server, it seems that the SDK tries to connect with a real amazon webservice server and it fails.
This is the code I am trying
Dim config As AmazonS3Config = New AmazonS3Config With {
.ForcePathStyle = True,
.ServiceURL = cloudEndpoint,
.RegionEndpoint = Amazon.RegionEndpoint.GetBySystemName(region)
}
config.Validate()
s3Client = New AmazonS3Client(cloudAccessKey, cloudSecretKey, config)
Dim listBuckets As ListBucketsResponse = s3Client.ListBuckets()
The S3Client is generated correctly but when I tried to get the buckets, I get the following exception:
Error creating s3. Exception: Amazon.Runtime.AmazonServiceException: A WebException with status ConnectFailure was thrown. ---> System.Net.WebException: Unable to connect to the remote server ---> System.Net.Sockets.SocketException: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond ** 52.216.143.230:80 **
at System.Net.Sockets.Socket.DoConnect(EndPoint endPointSnapshot, SocketAddress socketAddress)
at System.Net.ServicePoint.ConnectSocketInternal(Boolean connectFailure, Socket s4, Socket s6, Socket& socket, IPAddress& address, ConnectSocketState state, IAsyncResult asyncResult, Exception& exception)
--- End of inner exception stack trace ---
at System.Net.HttpWebRequest.GetResponse()
at Amazon.Runtime.Internal.HttpRequest.GetResponse()
at Amazon.Runtime.Internal.HttpHandler`1.InvokeSync(IExecutionContext executionContext)
at Amazon.Runtime.Internal.RedirectHandler.InvokeSync(IExecutionContext executionContext)
at Amazon.Runtime.Internal.Unmarshaller.InvokeSync(IExecutionContext executionContext)
at Amazon.S3.Internal.AmazonS3ResponseHandler.InvokeSync(IExecutionContext executionContext)
at Amazon.Runtime.Internal.ErrorHandler.InvokeSync(IExecutionContext executionContext)
--- End of inner exception stack trace ---
at TestS3.S3CDM..ctor(String endpoint, String accessKey, String secretKey, String region, String bucketName)
at TestS3.Form1.btn_CreateConnector_Click(Object sender, EventArgs e)
The server (52.216.143.230:80) that appears in the exception is not my s3 server, searching I find that it´s an amazon server.
Is it necessary connectivity to internet to use this SDK? Or I forget any additional configuration?
Thank you in advance.

Related

MQTTNet with MQTT.js are not working together

I'm trying to use MQTTNet as service broker, that takes requests from webClients over MQTT.js. However, this method is notworking for unknown reasons.
when i test the Service Broker using the windows application "MQTT Explorer" as a client, it works fine.
When i test the MQTT.js Client to connect to an open Service Broker like broker.emqx.io it works also fine.
but the connection between my service Broker with the mqtt client has always a problem. The following error is thrown from the MQTTNet Server:
Client '[::1]:58434' accepted by TCP listener '[::]:8883, ipv6'.
Expected at least 21538 bytes but there are only 69 bytes
MQTTnet.Exceptions.MqttProtocolViolationException: Expected at least 21538 bytes but there are
only 69 bytes
at MQTTnet.Formatter.MqttBufferReader.ReadString()
at MQTTnet.Formatter.MqttPacketFormatterAdapter.ParseProtocolVersion(ReceivedMqttPacket
receivedMqttPacket)
at MQTTnet.Formatter.MqttPacketFormatterAdapter.DetectProtocolVersion(ReceivedMqttPacket
receivedMqttPacket)
at MQTTnet.Adapter.MqttChannelAdapter.ReceivePacketAsync(CancellationToken cancellationToken)
at MQTTnet.Server.MqttClientSessionsManager.ReceiveConnectPacket(IMqttChannelAdapter
channelAdapter, CancellationToken cancellationToken)
at MQTTnet.Server.MqttClientSessionsManager.HandleClientConnectionAsync(IMqttChannelAdapter
channelAdapter, CancellationToken cancellationToken)
Client '[::1]:58434' disconnected at TCP listener '[::]:8883, ipv6'.
configuration of my server are as following:
static async Task<MqttServer> StartMqttServer(bool isDevelopment, ConsoleLogger consoleLogger = null)
{
MqttFactory mqttFactory = new MqttFactory();
if (consoleLogger != null)
{
mqttFactory = new MqttFactory(consoleLogger);
}
// Due to security reasons the "default" endpoint (which is unencrypted) is not enabled by default!
var mqttServerOptions = mqttFactory.CreateServerOptionsBuilder()
.WithDefaultEndpoint()
.Build();
var server = mqttFactory.CreateMqttServer(mqttServerOptions);
await server.StartAsync();
return server;
}
does anybody know why is this happening? And perhaps have an idea how i can fix it?
Thanks in advaced.

How to disable ssl certificate validation upon OpenId connect in .Net Core 3.1?

I'm trying to connect in a development environment to a open id authority with it's ip address. Obviously in this scenario the ssl validation will fail. I'd like to bypass it, without any luck so far. I've found the following answers regarding this topic:
Setting the RequireHttpsMetadata to false in the OpenIdConnectOptions class.
Using the code below:
ServicePointManager.ServerCertificateValidationCallback +=
(sender, cert, chain, sslPolicyErrors) => true;
When my app tries to access the oidc authority I recieve the same error:
An unhandled exception occurred while processing the request.
AuthenticationException: The remote certificate is invalid according
to the validation procedure.
System.Net.Security.SslStream.StartSendAuthResetSignal(ProtocolToken
message, AsyncProtocolRequest asyncRequest, ExceptionDispatchInfo
exception)
HttpRequestException: The SSL connection could not be established, see
inner exception.
System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Stream
stream, SslClientAuthenticationOptions sslOptions, CancellationToken
cancellationToken)
IOException: IDX20804: Unable to retrieve document from:
'https://172.11.0.11:1111/MY_APP/.well-known/openid-configuration'.
Microsoft.IdentityModel.Protocols.HttpDocumentRetriever.GetDocumentAsync(string
address, CancellationToken cancel)
InvalidOperationException: IDX20803: Unable to obtain configuration
from:
'https://172.11.0.11:1111/MY_APP/.well-known/openid-configuration'.
Microsoft.IdentityModel.Protocols.ConfigurationManager.GetConfigurationAsync(CancellationToken
cancel)
Warning: only use this during development. You need a custom certificate validation routine for your production platform if appropriate.
You might have overridden the wrong HttpClientHandler. Back-channel HttpClient for OpenId Connect can be overridden here:
services
.AddAuthentication(options =>
{
...
})
.AddCookie()
.AddOpenIdConnect(options =>
{
...
HttpClientHandler handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
options.BackchannelHttpHandler = handler;
});

How to make gRPC client comunicate with a gRPC server in a different machine? Both in Aspnet Core 3.0. Possible SSL problem

So, by the title you know what I'm trying to build.
I already have one gRPC server and 3 clients talking together in the same machine. The server is accessible on http://localhot:5001. Everything runs smoothly but if I run the clients on another machine they cannot access the server. So I installed IIS and placed the server there for it to get served to outside with the domain beta.server.com. I altered the hosts file on the client machine to go to the computer ip(192.168.5.49) where the server is running on IIS.
When I try to access with the browser by http i get a message saying i can only connect with a gRPC client. By https says NET::ERR_CERT_COMMON_NAME_INVALID. Maybe this is the problem...(found out after writing the rest).
By trying to connect with a gRPC client to http(http://beta.server.com) I get an error saying http/1.1 is not supported, which is true, this service works only on http2.
When try to connect to the server ip with https(https://beta.server.com) I get the error that the ssl connection could not be established. As follows:
PS C:\Users\Farm\Desktop\GrpcSierConsole\Viewer> dotnet run
Entered task
Unhandled exception. System.AggregateException: One or more errors occurred. (Status(StatusCode=Internal, Detail="Error starting gRPC call: The SSL connection could not be established, see inner exception."))
---> Grpc.Core.RpcException: Status(StatusCode=Internal, Detail="Error starting gRPC call: The SSL connection could not be established, see inner exception.")
at Grpc.Net.Client.Internal.HttpContentClientStreamReader`2.MoveNextCore(CancellationToken cancellationToken)
at Grpc.Core.AsyncStreamReaderExtensions.ReadAllAsync[T](IAsyncStreamReader`1 streamReader, CancellationToken cancellationToken)+MoveNext()
at Grpc.Core.AsyncStreamReaderExtensions.ReadAllAsync[T](IAsyncStreamReader`1 streamReader, CancellationToken cancellationToken)+System.Threading.Tasks.Sources.IValueTaskSource<System.Boolean>.GetResult()
at Viewer.Program.<>c.<<Main>b__0_0>d.MoveNext() in C:\Users\Farm\Desktop\GrpcSierConsole\viewer\Program.cs:line 24
--- End of stack trace from previous location where exception was thrown ---
at Viewer.Program.<>c.<<Main>b__0_0>d.MoveNext() in C:\Users\Farm\Desktop\GrpcSierConsole\viewer\Program.cs:line 24
--- End of inner exception stack trace ---
at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
at System.Threading.Tasks.Task.Wait(Int32 millisecondsTimeout, CancellationToken cancellationToken)
at System.Threading.Tasks.Task.Wait()
at Viewer.Program.Main() in C:\Users\Farm\Desktop\GrpcSierConsole\viewer\Program.cs:line 29
The error is on line 29 on the program.cs in the server. The code I have there is the following:
Line 29 is webBuilder.UseStartup():
//Additional configuration is required to successfully run gRPC on macOS.
// For instructions on how to configure Kestrel and gRPC clients on macOS, visit https://go.microsoft.com/fwlink/?linkid=2099682
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
I've tried to use the Visual Studio localhost certificate and a self signed certificate within the IIS in both the client computer and the server computer running IIS.
Also I've used this line in the client to trust all certificates:
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
Which I got from: How to ignore the certificate check when ssl
I don't know what more to do. Anyone can help?
##################### UPDATE ######################
I've added this code to the client
var httpClientHandler = new HttpClientHandler();
// Return `true` to allow certificates that are untrusted/invalid
httpClientHandler.ServerCertificateCustomValidationCallback =
HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
var httpClient = new HttpClient(httpClientHandler);
var channel = GrpcChannel.ForAddress("https://localhost:5001",
new GrpcChannelOptions { HttpClient = httpClient });
var client = new QueueManagement.QueueManagementClient(channel);
...
Now I don't have the SSL error but this one:
PS C:\Users\Farm\Desktop\GrpcSierConsole\Viewer> dotnet run
Entered task
Unhandled exception. System.AggregateException: One or more errors occurred. (Status(StatusCode=Internal, Detail="Error starting gRPC call: An error occurred while sending the request."))
---> Grpc.Core.RpcException: Status(StatusCode=Internal, Detail="Error starting gRPC call: An error occurred while sending the request.")
at Grpc.Net.Client.Internal.HttpContentClientStreamReader`2.MoveNextCore(CancellationToken cancellationToken)
at Grpc.Core.AsyncStreamReaderExtensions.ReadAllAsync[T](IAsyncStreamReader`1 streamReader, CancellationToken cancellationToken)+MoveNext()
at Grpc.Core.AsyncStreamReaderExtensions.ReadAllAsync[T](IAsyncStreamReader`1 streamReader, CancellationToken cancellationToken)+System.Threading.Tasks.Sources.IValueTaskSource<System.Boolean>.GetResult()
at Viewer.Program.<>c.<<Main>b__0_0>d.MoveNext() in C:\Users\Farm\Desktop\GrpcSierConsole\Viewer\Program.cs:line 32
--- End of stack trace from previous location where exception was thrown ---
at Viewer.Program.<>c.<<Main>b__0_0>d.MoveNext() in C:\Users\Farm\Desktop\GrpcSierConsole\Viewer\Program.cs:line 32
--- End of inner exception stack trace ---
at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
at System.Threading.Tasks.Task.Wait(Int32 millisecondsTimeout, CancellationToken cancellationToken)
at System.Threading.Tasks.Task.Wait()
at Viewer.Program.Main() in C:\Users\Farm\Desktop\GrpcSierConsole\Viewer\Program.cs:line 37
And at line 37 i have the task.wait() because this runs inside a task.
var channel = GrpcChannel.ForAddress("https://beta.server.com",
new GrpcChannelOptions { HttpClient = httpClient });
var client = new QueueManagement.QueueManagementClient(channel);
var request = client.QueueNumberChanged(new SendQueueId { QueueId = "2" });
await foreach (var response in request.ResponseStream.ReadAllAsync())
{
Console.WriteLine($"Senha {response.Number} -> fila 2");
}
});
t.Wait();
After a great research and many messages exchanged in Issues at Microsoft official GitHub Repository for .Net Core kestrel documentation i found it.
It can be done with this settings on appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"Kestrel": {
"EndpointDefaults": {
"Protocols": "Http2"
},
"EndPoints": {
"Https": {
"Url": "https://*:5002",
"Certificate": {
"Path": "c:\\test.pfx",
"Password": "password1234"
}
}
}
},
}

AzureServiceTokenProviderException using key vault

I don't know what is wrong, anyone got any ideas? I just followed this tutorial: https://learn.microsoft.com/da-dk/azure/key-vault/vs-key-vault-add-connected-service#feedback
This error only happens when the website gets published to Azure.
AzureServiceTokenProviderException: Parameters: Connection String: [No connection string specified], Resource: https://vault.azure.net, Authority: https://login.windows.net/1855fd54-8283-4d57-ab22-4e818e22fcf7. Exception Message: Tried the following 3 methods to get an access token, but none of them worked.
Parameters: Connection String: [No connection string specified], Resource: https://vault.azure.net, Authority: https://login.windows.net/1855fd54-8283-4d57-ab22-4e818e22fcf7. Exception Message: Tried to get token using Managed Service Identity. Access token could not be acquired. An attempt was made to access a socket in a way forbidden by its access permissions.
Parameters: Connection String: [No connection string specified], Resource: https://vault.azure.net, Authority: https://login.windows.net/1855fd54-8283-4d57-ab22-4e818e22fcf7. Exception Message: Tried to get token using Visual Studio. Access token could not be acquired. Visual Studio Token provider file not found at "D:\local\LocalAppData\.IdentityService\AzureServiceAuth\tokenprovider.json"
Parameters: Connection String: [No connection string specified], Resource: https://vault.azure.net, Authority: https://login.windows.net/1855fd54-8283-4d57-ab22-4e818e22fcf7. Exception Message: Tried to get token using Azure CLI. Access token could not be acquired. 'az' is not recognized as an internal or external command,
operable program or batch file.
Microsoft.Azure.Services.AppAuthentication.AzureServiceTokenProvider.GetAuthResultAsyncImpl(string resource, string authority, CancellationToken cancellationToken)
AzureServiceTokenProviderException: Parameters: Connection String: [No connection string specified], Resource: https://vault.azure.net, Authority: https://login.windows.net/1855fd54-8283-4d57-ab22-4e818e22fcf7. Exception Message: Tried the following 3 methods to get an access token, but none of them worked. Parameters: Connection String: [No connection string specified], Resource: https://vault.azure.net, Authority: https://login.windows.net/1855fd54-8283-4d57-ab22-4e818e22fcf7. Exception Message: Tried to get token using Managed Service Identity. Access token could not be acquired. An attempt was made to access a socket in a way forbidden by its access permissions. Parameters: Connection String: [No connection string specified], Resource: https://vault.azure.net, Authority: https://login.windows.net/1855fd54-8283-4d57-ab22-4e818e22fcf7. Exception Message: Tried to get token using Visual Studio. Access token could not be acquired. Visual Studio Token provider file not found at "D:\local\LocalAppData\.IdentityService\AzureServiceAuth\tokenprovider.json" Parameters: Connection String: [No connection string specified], Resource: https://vault.azure.net, Authority: https://login.windows.net/1855fd54-8283-4d57-ab22-4e818e22fcf7. Exception Message: Tried to get token using Azure CLI. Access token could not be acquired. 'az' is not recognized as an internal or external command, operable program or batch file.
Microsoft.Azure.Services.AppAuthentication.AzureServiceTokenProvider.GetAuthResultAsyncImpl(string resource, string authority, CancellationToken cancellationToken)
Microsoft.Azure.Services.AppAuthentication.AzureServiceTokenProvider.<get_KeyVaultTokenCallback>b__8_0(string authority, string resource, string scope)
FindEnBar.Program+<>c__DisplayClass2_0+<<SetupConfiguration>g__GetToken|0>d.MoveNext() in Program.cs
Microsoft.Azure.KeyVault.KeyVaultCredential.PostAuthenticate(HttpResponseMessage response)
Microsoft.Azure.KeyVault.KeyVaultCredential.ProcessHttpRequestAsync(HttpRequestMessage request, CancellationToken cancellationToken)
Microsoft.Azure.KeyVault.KeyVaultClient.GetSecretsWithHttpMessagesAsync(string vaultBaseUrl, Nullable<int> maxresults, Dictionary<string, List<string>> customHeaders, CancellationToken cancellationToken)
Microsoft.Azure.KeyVault.KeyVaultClientExtensions.GetSecretsAsync(IKeyVaultClient operations, string vaultBaseUrl, Nullable<int> maxresults, CancellationToken cancellationToken)
Microsoft.Extensions.Configuration.AzureKeyVault.AzureKeyVaultConfigurationProvider.LoadAsync()
Microsoft.Extensions.Configuration.AzureKeyVault.AzureKeyVaultConfigurationProvider.Load()
Microsoft.Extensions.Configuration.ConfigurationRoot..ctor(IList<IConfigurationProvider> providers)
Microsoft.Extensions.Configuration.ConfigurationBuilder.Build()
Microsoft.Extensions.Hosting.HostBuilder.BuildAppConfiguration()
Microsoft.Extensions.Hosting.HostBuilder.Build()```
I got something similar after changing my acount password. After logging out and back in again in VS2019 or VS2022, the exception went away.
In the tutorial, it uses Azure Managed Identity to access Key Vault.
See the following code:
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((ctx, builder) =>
{
var keyVaultEndpoint = GetKeyVaultEndpoint();
if (!string.IsNullOrEmpty(keyVaultEndpoint))
{
var azureServiceTokenProvider = new AzureServiceTokenProvider();
var keyVaultClient = new KeyVaultClient(
new KeyVaultClient.AuthenticationCallback(
azureServiceTokenProvider.KeyVaultTokenCallback));
builder.AddAzureKeyVault(
keyVaultEndpoint, keyVaultClient, new DefaultKeyVaultSecretManager());
}
}
).UseStartup<Startup>();
In your local development, it will use the user credential of VS or use the credential stored by Azure CLI.
However, in the cloud, you need to turn on the identity of your VM or Web App. And then add access policy for that identity in Key Vault.
Then, your code would be able to use Key Vault without any problem.

Access self signed X509certificates in XamarinForms for mqtt TLS connection to a Mosquitto broker

I desire to TLS secure with a self signed x509certificate a number of existing XamarinForms apps that connect to a mosquitto mqtt broker using the M2MqttDotnetCore client.
To that end I have created a simple sample XamarinForms pub/sub chat app to learn how to secure an XamarinForms mqtt client application that can be sound in this GitHub repository. jhalbrecht/XamarinFormsMqttSample
I have samples in Mosquitto_pub, python and a .net console app that accomplish this goal of successfully connecting to a mosquitto broker over port 8883 with TLS and a self signed certificate. The XamarinForms UWP app also works unsecured and secured. I'm having trouble getting the Android app to work with TLS on port 8883, The Android app does work unsecured on port 1883. This is the runtime log from 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
The way I am currently loading and accessing the X509certificates is not secure or a best practice. It works. I hope to eventually learn how to access the device ca keystores for each mobile platform. I use the cross-platform plug-in FilePicker to load a cert, base64 encode it, and save it.
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);
I have reached out to a few Xamarin folks via twitter. I have an open issue in my above mentioned repository discussing the problem where #baulig from Microsoft has I believe given me the answer however I don't currently know how to implement it.
I just looked at the certificate validation code and what it does is
essentially
var certStore = KeyStore.GetInstance ("AndroidCAStore");
certStore.Load(null);
This is the entry point:
https://github.com/mono/mono/blob/master/mcs/class/System/Mono.Btls/MonoBtlsX509LookupAndroid.cs,
it calls this code
https://github.com/mono/mono/blob/master/mcs/class/System/System/AndroidPlatform.cs#L101
which then calls into xamarin-android code here:
https://github.com/xamarin/xamarin-android/blob/master/src/Mono.Android/Android.Runtime/AndroidEnvironment.cs
The KeyStore should be this class:
https://developer.xamarin.com/api/type/Java.Security.KeyStore/.
So you should be able to do this via Java.Security.KeyStore.
What permissions are necessary to grant in AndroidManifest.xml?
What terms might I research to properly access the platform ca keystores?
Additions after initial posting
February 27, 2019 (MST) 2:51 PM
Added certs and mqtt client creation from MqttDataService.cs
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
);
Since you are using .Net's/Mono Socket (via M2MqttDotnetCore), just use cert pinning and you only have to handle the RemoteCertificateValidationCallback. Thus no messing with Android's trusted stores, etc...
SslStream Usage on Android:
Note: There are issues with SslStream on Android, object allocations can go crazy... I believe(?) there is an open issue about this. (I had to use Java's SSLSocket a couple times to work around this issue)
Enable Native TLS 1.2+
Using BoringSSL via the Android project build options
Add your cert to the Android's Asset directory:
├── Assets
│   └── sushihangover.cert
This is your cert/.pem file (NOT your KEY!!)
Make sure that this is an ascii file with no unicode BOM header
Via openssl example (just change it to your host and secure port)
echo -n | openssl s_client -connect 10.1.10.250:5001 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p'
RemoteCertificateValidationCallback Implementation
Note: The following code can be in used in NetStd2.0 or 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;
}
SSLStream Usage Example:
Note: This is connecting to a NetCore Web API port using a self-signed cert
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();
}
Server cert mismatch error:
If your server cert (self-signed or not) does not match the one that you are pinning to, you will receive:
{Mono.Btls.MonoBtlsException: Ssl error:1000007d:SSL routines:OPENSSL_internal:CERTIFICATE_VERIFY_FAILED