I have the following issue: I have built a webservice that is supposed to run as an Azure Webservice, which calls an external API retrieve some data. For the connection, the external company has provided me with a certificate which I succesfully stored in the Azure Keyvault. After some trial and error I managed to verify that the certificate is succesfully being retrieved from the vault as I locally tested the code block below. This resulted in a success response with the data I wanted to retrieve. So far so good - until I publish this to Azure. Everything seems to work fine, however I get the following error message:
Received an unexpected EOF or 0 bytes from the transport stream
I have exhausted the first 5 pages of google. I keep finding answers regarding TLS, but I explicitly set it to the correct version as I tested the options (even in this code snippet, i am actually good only using TLS 1.2).
What causes this? Is it some mysterious Azure config setting that I am missing? As I said, the code works 100% on my computer. The issue seems not to be the key or the vault. The biggest difference is that locally I run the code as the tenant admin, however I provided the app service with a managed identity with the correct permissions to the keyvault.
I will also provide the stacktrace. var result = await client.GetAsync(url);
The error is thrown at
var result = await client.GetAsync(url);
I hope I have provided enough information. Thank you in advance
Code snippet:
public async Task<string>GetData(string url) {
try {
var client = await GetHttpClient();
var result = await client.GetAsync(url);
if (result.IsSuccessStatusCode) {
var content = await result.Content.ReadAsStringAsync();
return content;
} else {
Exception ex = new Exception("Failed getting data: " + result.Content.ReadAsStringAsync().Result);
throw ex;
}
} catch (Exception ex) {
_telemetry.TrackException(ex);
throw;
}
}
public async Task<HttpClient> GetHttpClient() {
var cert = await GetCertFromVault();
var handler = new HttpClientHandler() {
ClientCertificateOptions = ClientCertificateOption.Manual,
SslProtocols = SslProtocols.Tls
| SslProtocols.Tls11
| SslProtocols.Tls12,
};
handler.ClientCertificates.Add(cert);
handler.ServerCertificateCustomValidationCallback = (message, certificate2, arg3, arg4) => true;
var client = new HttpClient(handler);
return client;
}
async Task<X509Certificate2> GetCertFromVault() {
try {
string keyVaultUrl = _configuration["KeyVault"];
string certKeyName = _configuration["CertKeyName"];
var cred = new DefaultAzureCredential();
//Get certificate as secret as to include the key:
var keyVaultClient = new SecretClient(new Uri(keyVaultUrl), cred);
var certResponse = await keyVaultClient.GetSecretAsync(certKeyName);
byte[] cert = System.Convert.FromBase64String(certResponse.Value.Value);
//Convert retrieved values to X509Certificate2
var resultKey = new X509Certificate2(cert, "", X509KeyStorageFlags.MachineKeySet
| X509KeyStorageFlags.PersistKeySet
| X509KeyStorageFlags.Exportable);
return resultKey;
} catch (Exception ex) {
_telemetry.TrackException(ex);
throw;
}
}
Stacktrace:
System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception.
---> System.IO.IOException: Received an unexpected EOF or 0 bytes from the transport stream.
at System.Net.Security.SslStream.<FillHandshakeBufferAsync>g__InternalFillHandshakeBufferAsync|182_0[TIOAdapter](TIOAdapter adap, ValueTask`1 task, Int32 minSize)
at System.Net.Security.SslStream.ReceiveBlobAsync[TIOAdapter](TIOAdapter adapter)
at System.Net.Security.SslStream.ForceAuthenticationAsync[TIOAdapter](TIOAdapter adapter, Boolean receiveFirst, Byte[] reAuthenticationData, Boolean isApm)
at System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Boolean async, Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken)
--- End of inner exception stack trace ---
at System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Boolean async, Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.GetHttpConnectionAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken)
at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.DiagnosticsHandler.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpClient.SendAsyncCore(HttpRequestMessage request, HttpCompletionOption completionOption, Boolean async, Boolean emitTelemetryStartStop, CancellationToken cancellationToken)
at MyService.MyClient.GetData(String url) in [path]\MyClient.cs:line 40
Line 40 corresponds with
var result = await client.GetAsync(url);