I need to implement an API integration with Itaú bank (in Brazil).
There is a first call to authenticate and then I would call the action I need. But it won't go passed the authentication point.
I get the exception "The request was aborted: Could not create SSL/TLS secure channel." when using .NET Framework 4.8 on the published application.
I have the following code that returns the exception "The request was aborted: Could not create SSL/TLS secure channel.":
'.NET Framework 2.0
Public Sub New()
ServicePointManager.ServerCertificateValidationCallback = New RemoteCertificateValidationCallback(AddressOf ValidateServerCertificate)
ServicePointManager.SecurityProtocol = CType(&HC00, Net.SecurityProtocolType)
End Sub
Public Function ValidateServerCertificate(ByVal sender As Object, ByVal certificate As X509Certificate, ByVal chain As X509Chain, ByVal sslPolicyErrors As SslPolicyErrors) As Boolean
Return True
End Function
'.NET Framework 4.8
Private ReadOnly Property Certificado As X509Certificate2
Get
If m_Certificado Is Nothing Then
Dim assembly As Assembly = Assembly.GetExecutingAssembly()
Using stream As Stream = assembly.GetManifestResourceStream(GetType(AppModule), "certificado.pfx")
If stream Is Nothing Then
Throw New ApplicationException("Certificado não encontrado.")
End If
Dim rawData(CInt(stream.Length)) As Byte
stream.Read(rawData, 0, rawData.Length)
m_Certificado = New X509Certificate2(rawData, "PASSWORD")
End Using
End If
Return m_Certificado
End Get
End Property
Public Function EnviarAutenticacao() As RetornoRequisicao
Dim handler As New WebRequestHandler()
Dim httpContent As StringContent = Nothing
Dim responseMessage As HttpResponseMessage = Nothing
Dim resposta As New RetornoRequisicao
Dim sClient As String = ""
Dim contentData As String = "grant_type=client_credentials&client_id=CLIENT_ID&client_secret=CLIENT_SECRET"
Try
handler.ClientCertificates.Add(Certificado)
'With the 2 lines below, removing them from the constructor or leaving them in the constructor and removing from here
handler.SslProtocols = System.Security.Authentication.SslProtocols.Tls12
handler.ServerCertificateValidationCallback = New RemoteCertificateValidationCallback(AddressOf ValidateServerCertificate)
Using client As New HttpClient(handler)
Try
httpContent = New StringContent(contentData, TextEncoding, "application/x-www-form-urlencoded")
responseMessage = client.PostAsync(URLAutenticacao, httpContent).GetAwaiter().GetResult()
If responseMessage.IsSuccessStatusCode Then
resposta.Status = CInt(HttpStatusCode.OK)
Else
resposta.Status = CInt(responseMessage.StatusCode)
End If
resposta.Conteudo = responseMessage.Content.ReadAsStringAsync().GetAwaiter().GetResult()
Finally
Try
sClient = JsonConvert.SerializeObject(client, ErrorSerializerSettings)
Catch
End Try
End Try
End Using
Catch ex As Exception
Dim sbMensagem As New StringBuilder
sbMensagem.AppendLine("Erro ao Autenticar")
Try
sbMensagem.AppendLine($"Handler:{vbCrLf}{JsonConvert.SerializeObject(handler, ErrorSerializerSettings)}")
Catch
End Try
If Not String.IsNullOrEmpty(sClient) Then
sbMensagem.AppendLine($"Client:{vbCrLf}{sClient}")
End If
Try
sbMensagem.AppendLine($"Certificate:{vbCrLf}{JsonConvert.SerializeObject(Certificado, ErrorSerializerSettings)}")
Catch
End Try
If Not String.IsNullOrEmpty(contentData) Then
sbMensagem.AppendLine($"Content Data:{vbCrLf}{contentData}")
End If
If httpContent IsNot Nothing Then
Try
sbMensagem.AppendLine($"Http Content:{vbCrLf}{JsonConvert.SerializeObject(httpContent, ErrorSerializerSettings)}")
Catch
End Try
End If
If responseMessage IsNot Nothing Then
Try
sbMensagem.AppendLine($"Response Message:{vbCrLf}{JsonConvert.SerializeObject(responseMessage, ErrorSerializerSettings)}")
Catch
End Try
End If
Try
sbMensagem.AppendLine($"Resposta:{vbCrLf}{JsonConvert.SerializeObject(resposta, ErrorSerializerSettings)}")
Catch
End Try
Throw New ApplicationException(sbMensagem.ToString, ex)
End Try
Return resposta
End Function
I've tried different approaches to sending the request, such as the following, receiving the same error:
'.NET Framework 4.8
Protected Overrides Function EnviarAutenticacao() As RetornoRequisicao
Dim request As HttpWebRequest = Nothing
Dim requestResponse As HttpWebResponse = Nothing
Dim resposta As New RetornoRequisicao
Try
request = CType(WebRequest.Create(URLAutenticacao), HttpWebRequest)
request.ContentType = "application/x-www-form-urlencoded"
request.Method = TipoEnvioAutenticacao
request.ServerCertificateValidationCallback = New RemoteCertificateValidationCallback(AddressOf ValidateServerCertificate)
Dim dataBody As String = "grant_type=client_credentials&client_id=CLIENT_ID&client_secret=CLIENT_SECRET"
Dim body As Byte() = Encoding.ASCII.GetBytes(dataBody)
request.ContentLength = body.Length
Dim myWriter As Stream = Nothing
request.ClientCertificates.Add(Certificado)
myWriter = request.GetRequestStream()
myWriter.Write(body, 0, body.Length)
requestResponse = CType(request.GetResponse(), HttpWebResponse)
resposta.Conteudo = New StreamReader(requestResponse.GetResponseStream()).ReadToEnd()
If requestResponse.StatusCode >= 200 AndAlso requestResponse.StatusCode <= 299 Then
resposta.Status = CInt(HttpStatusCode.OK)
Else
resposta.Status = CInt(requestResponse.StatusCode)
End If
Catch ex As Exception
Dim sbMensagem As New StringBuilder
sbMensagem.AppendLine("Erro ao Autenticar")
Try
sbMensagem.AppendLine($"Request:{vbCrLf}{JsonConvert.SerializeObject(request, ErrorSerializerSettings)}")
Catch
End Try
If requestResponse IsNot Nothing Then
Try
sbMensagem.AppendLine($"Request Response:{vbCrLf}{JsonConvert.SerializeObject(requestResponse, ErrorSerializerSettings)}")
Catch
End Try
End If
Try
sbMensagem.AppendLine($"Resposta:{vbCrLf}{JsonConvert.SerializeObject(resposta, ErrorSerializerSettings)}")
Catch
End Try
Throw New ApplicationException(sbMensagem.ToString, ex)
End Try
Return resposta
End Function
This is a VB.NET web forms application with the web application and a project running on .NET Framework 4.8 and another project running on .NET Framework 2.0. The .NET Framework 4.8 project has a reference to the .NET Framework 2.0 project. The code above shows where each method is. The server is a Windows Server 2019 Standard.
Everything works fine while debuging on Visual Studio 2022 but doesn't when published on the server. On IIS the application pool is set to use .NET CLR version 4.0.30319. I tried installing the .NET Framework 4.8 Runtime on the server and it says it already has that or later version installed.
Below is the sbMensagem from the Catch with the Stack Trace:
Error Message:
Erro ao Autenticar
Handler:
{
"AuthenticationLevel": 1,
"ImpersonationLevel": 4,
"AllowPipelining": true,
"UnsafeAuthenticatedConnectionSharing": false,
"MaxResponseHeadersLength": 64,
"ReadWriteTimeout": 300000,
"CachePolicy": {
"Level": 1
},
"ContinueTimeout": "00:00:00.3500000",
"ClientCertificates": [
{
"RawData": "RAW_DATA"
}
],
"ServerCertificateValidationCallback": null,
"CheckCertificateRevocationList": false,
"DefaultProxyCredentials": null,
"MaxConnectionsPerServer": 2147483647,
"Properties": {},
"ServerCertificateCustomValidationCallback": null,
"SslProtocols": 0,
"SupportsAutomaticDecompression": true,
"SupportsProxy": true,
"SupportsRedirectConfiguration": true,
"UseCookies": true,
"CookieContainer": {
"Capacity": 300,
"Count": 0,
"MaxCookieSize": 4096,
"PerDomainCapacity": 20
},
"ClientCertificateOptions": 0,
"AutomaticDecompression": 0,
"UseProxy": true,
"Proxy": null,
"PreAuthenticate": false,
"UseDefaultCredentials": false,
"Credentials": null,
"AllowAutoRedirect": true,
"MaxAutomaticRedirections": 50,
"MaxRequestContentBufferSize": 2147483647
}
Client:
{
"DefaultRequestHeaders": [],
"BaseAddress": null,
"Timeout": "00:01:40",
"MaxResponseContentBufferSize": 2147483647
}
Certificate:
{
"RawData": "RAW_DATA"
}
Content Data:
grant_type=client_credentials&client_id=CLIENT_ID&client_secret=CLIENT_SECRET
Http Content:
{
"Headers": [
{
"Key": "Content-Type",
"Value": [
"application/x-www-form-urlencoded; charset=utf-8"
]
},
{
"Key": "Content-Length",
"Value": [
"127"
]
}
]
}
Resposta:
{
"Status": 0,
"Conteudo": null
}
Exception ToString: System.Net.Http.HttpRequestException: An error occurred while sending the request. ---> System.Net.WebException: The request was aborted: Could not create SSL/TLS secure channel.
at System.Net.HttpWebRequest.EndGetRequestStream(IAsyncResult asyncResult, TransportContext& context)
at System.Net.Http.HttpClientHandler.GetRequestStreamCallback(IAsyncResult ar)
--- End of inner exception stack trace ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at SIARM.NFSE.Data.ArrecadacaoPIXAPIItau.EnviarAutenticacao()
(System.ApplicationException)
at SIARM.NFSE.Data.ArrecadacaoPIXAPIItau.EnviarAutenticacao()
at SIARM.NFSE.Data.ArrecadacaoPIXAPI.Autenticar()
Error Message:
An error occurred while sending the request. (System.Net.Http.HttpRequestException)
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at ArrecadacaoPIXAPIItau.EnviarAutenticacao()
Error Message:
The request was aborted: Could not create SSL/TLS secure channel. (System.Net.WebException)
at System.Net.HttpWebRequest.EndGetRequestStream(IAsyncResult asyncResult, TransportContext& context)
at System.Net.Http.HttpClientHandler.GetRequestStreamCallback(IAsyncResult ar)
It turns out we had to change a configuration on the IIS Application pool (got the answer from https://stackoverflow.com/a/27242467/8508096)