How can I make a TLS connection using Vala? - glib

I'm trying to figure out how can I make a proper TLS connection using Gio. The Gio documentation says you can create a TLS connection just by setting the tls flag on the SocketClient. Below is a Gio networking sample from the gnome wiki. When I set the tls flag, the TLS layer is configured automatically but validating the certificates fails unless I skip the validation.
Do I have to validate certificates myself or is GLib supposed to do the validation? Can somebody provide a full example on how to use TLS in Vala?
var host = "developer.gnome.org";
try {
// Resolve hostname to IP address
var resolver = Resolver.get_default ();
var addresses = resolver.lookup_by_name (host, null);
var address = addresses.nth_data (0);
print (#"Resolved $host to $address\n");
// Connect
var client = new SocketClient ();
client.set_tls(true);
// skips certificate validation
client.set_tls_validation_flags( 0 );
var conn = client.connect (new InetSocketAddress (address, 443));
print (#"Connected to $host\n");
// Send HTTP GET request
var message = #"GET / HTTP/1.1\r\nHost: $host\r\n\r\n";
conn.output_stream.write (message.data);
print ("Wrote request\n");
// Receive response
var response = new DataInputStream (conn.input_stream);
var status_line = response.read_line (null).strip ();
print ("Received status line: %s\n", status_line);
} catch (Error e) {
stderr.printf ("%s\n", e.message);
}
And another thing I want to ask is; when I run the code above I get this output:
Resolved developer.gnome.org to 8.43.85.14
Connected to developer.gnome.org
Wrote request
Received status line: HTTP/1.1 200 OK
But when I try to connect 'developer.mozilla.org', I'm getting the following error:
Resolved developer.mozilla.org to 54.192.235.2
Error performing TLS handshake: A packet with illegal or unsupported version was received.
Can anybody tell me the reason why I am getting this error? (By the way the version of GLib installed on my system is 2.64.6)

What you're doing so far is mostly correct, but you will probably want to do a little bit more to handle potential certificate errors during the TLS handshaking (see below).
Do I have to validate certificates myself or is GLib supposed to do the validation?
Note that SocketClient.set_tls_validation_flags is deprecated. To handle validation errors you can connect to the accept_certificate signal on the TlsClientConnection prior to handshaking:
var client = new SocketClient ();
client.set_tls(true);
client.event.connect ((SocketClientEvent event, SocketConnectable connectable, IOStream? connection) => {
if (event == SocketClientEvent.TLS_HANDSHAKING) {
((TlsClientConnection) connection).accept_certificate.connect ((peer_cert, errors) => {
// Return true to accept, false to reject
});
}
});
The errors are GLib.TlsCertificateFlags, so you'll want to determine which (if any) are acceptable. Ideally if there are any errors you would reject the certificate altogether, but if you want to allow self-signed certificates for example, that is possible this way.
You can simply check against the flags to see which ones are included in the errors:
TlsCertificateFlags[] flags = new TlsCertificateFlags[] {
TlsCertificateFlags.BAD_IDENTITY,
TlsCertificateFlags.EXPIRED,
TlsCertificateFlags.GENERIC_ERROR,
TlsCertificateFlags.INSECURE,
TlsCertificateFlags.NOT_ACTIVATED,
TlsCertificateFlags.REVOKED,
TlsCertificateFlags.UNKNOWN_CA
};
foreach (var flag in flags) {
if ((errors & flag) != 0) {
// The flag was included in the errors - respond accordingly
}
}
But when I try to connect 'developer.mozilla.org', I'm getting the
following error:
Resolved developer.mozilla.org to 54.192.235.2 Error performing TLS
handshake: A packet with illegal or unsupported version was received.
Can anybody tell me the reason why I am getting this error? (By the
way the version of GLib installed on my system is 2.64.6)
This is probably due to developer.mozilla.org using an old implementation of TLS (probably 1.0 or 1.1). These were disabled in GLib networking as of 2.64.x according to this bug report: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=954742
They may have upgraded to TLS 1.2 since you posted this question - I just did a quick test and connected using TLSv1.2 successfully.

Try run the program with export G_MESSAGES_DEBUG=all for full debug messages.
Also, for a full working example of code that uses TLS written in Vala via GIO, check out the code for this Gemini browser: https://github.com/koyuspace/fossil/blob/main/src/util/connection_helper.vala
I hope that this is somewhat useful to you.

Related

HTTPS SSL Connection not trusted, despite certificate being fine

I have got 2 sitest hosted on Windows 2012 R2 IIs 8.5.
One is instance of umbraco while other is .Net core based api (Lets call it MyApi).
I want to perform certain search action on umbraco so umbraco makes call to the api which calls back the Umbraco/Api. Call to the MyApi is fine, however the call from MyApi to the Umbraco/Api is problem. The Umbraco api logs:
Search failed System.Net.Http.HttpRequestException: An error occurred while sending the request. ---> System.Net.WebException: The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel. ---> System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure.
Certificates themselves are provided by our customer's inner authority, which is trusted root in server storage. Now originaly we have had problem with certificates, as they missed first DNS record we use for api call (the DNS records are not created yet, we use record in 'hosts') but that shoud be fiex by now.
I have updated the SSL error handler in the code so it logs an error and number in SSL Enum.
System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
System.Net.ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) =>
{
_logger.LogError("Received TLS errror " + ((int)sslPolicyErrors).ToString());
return false;
};
_logger.LogDebug("Search starting");
if (model.Username != null)
{
model.Favourites = _workplaceContext.GetUserFavourites(_dataContext, model.Username);
}
else if (model.JustFavourites)
{
return BadRequest();
}
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(_configuration.GetValue<string>("UmbracoApiUrl"));
_logger.LogDebug("Searching for addres " + new Uri(_configuration.GetValue<string>("UmbracoApiUrl")));
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
var json = JsonConvert.SerializeObject(model);
using (var stringContent = new StringContent(json, Encoding.UTF8, "application/json"))
{
var response = await client.PostAsync("workplace/search", stringContent);
if (response.IsSuccessStatusCode)
{
_logger.LogDebug("Search API Call success");
var jsonResponse = await response.Content.ReadAsStringAsync();
var responseModel = JsonConvert.DeserializeObject<SearchResponseModel>(jsonResponse);
_logger.LogDebug("Search response TotalCount = " + responseModel.TotalCount);
return responseModel;
}
else
{
_logger.LogDebug("Search API Call status - " + response.StatusCode);
return StatusCode((int)response.StatusCode);
}
}
}
Originaly we received number 2 error. Now we just receive number 0, which should be no problem. Despite that, connections is still not working. I have read various articles regarfding this and enabled troubleshooting through in web config of umbraco, but haven't found any useful information. I need method to troubleshoot the MyApi. Could somone point me a direction how to troubleshoot it to the similar degree of detail as umbraco (i am not much familiar with .NET core apps)?
The interesting part of error log:
2019-07-08 13:35:32.1745||DEBUG|XXXApi.Controllers.WorkplaceController|Search starting
2019-07-08 13:35:32.1901||DEBUG|XXXApi.Controllers.WorkplaceController|Searching for addres https://xxx.yy.zz/umbraco/api/
2019-07-08 13:35:32.2682||ERROR|XXXCApi.Controllers.WorkplaceController|Received TLS errror 0
2019-07-08 13:35:32.2682||ERROR|XXXApi.Controllers.WorkplaceController|Search failed System.Net.Http.HttpRequestException: An error occurred while sending the request. ---> System.Net.WebException: The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel. ---> System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure.
at System.Net.TlsStream.EndWrite(IAsyncResult asyncResult)
at System.Net.PooledStream.EndWrite(IAsyncResult asyncResult)
at System.Net.ConnectStream.WriteHeadersCallback(IAsyncResult ar)
--- End of inner exception stack trace ---
Solution: The original error was in certificate and got fixed, BUT the callback returning false I used for debugging caused problem marking connection unsuccessful. It took like 2 days to figure it out. So since moment i got 0 in enum, it was just bug in my debugging code.
Oh and don't forget to unsubscribe the delgate.

SNMPsharpnet SnmpNetworkException: 'Network error: connection reset by peer.'

I am beginner in C# and I am trying to create a tool to read snmp OID for some of my devices.
In general the system is working fine at the exception of when I cannot reach the IP address or when the IP Address is not using the same OID.
What I would like to achieve is : In case the device is not reachable : skip to the next one . In case the device has not the right OID : skip to the next one.
Currently when it happens I have an error like this one :
Error
SnmpSharpNet.SnmpNetworkException: 'Network error: connection reset by peer.'
Caused by
SnmpV1Packet result = (SnmpV1Packet)target.Request(pdu, param);
Sample of my code
//Start
UdpTarget target = new UdpTarget((IPAddress)agent, 161, 2000, 1);
Pdu pdu = new Pdu(PduType.Get);
pdu.VbList.Add(".1.3.6.1.4.1.1552.21.3.1.1.5.1.0");
pdu.VbList.Add(".1.3.6.1.4.1.1552.21.3.1.1.5.2.0");
pdu.VbList.Add(".1.3.6.1.4.1.1552.21.3.1.1.5.7.0");
pdu.VbList.Add(".1.3.6.1.4.1.1552.21.3.1.1.5.8.0");
// Make SNMP request
SnmpV1Packet result = (SnmpV1Packet)target.Request(pdu, param);
// If result is null then agent didn't reply or we couldn't parse the reply.
if (result != null)
{
if (result.Pdu.ErrorStatus != 0)
{
// agent reported an error with the request
MessageBox.Show("Error");
}
Thank you for your help
I have faced the same issue and the solution was to install SNMP Service on your windows and it should start working fine
this link should help you https://support.microsoft.com/en-us/help/324263/how-to-configure-the-simple-network-management-protocol-snmp-service-i

SSPI negotiation failed WSTrustChannelFactory

This one has me for a while now, I am trying to build a console app that can call a .net web/wcf service SP, the first leg is to get a token from the idP (ADFS4.0) the pasted code was working fine for a whole day, at some point it stopped working with the following error:
SOAP security negotiation with 'https://adfs.domain.in/adfs/services/trust/13/windowsmixed' for target 'https://adfs.domain.in/adfs/services/trust/13/windowsmixed' failed. See inner exception for more details.
The inner error is:
The Security Support Provider Interface (SSPI) negotiation failed.
NativeErrorCode: 0x80090350 -> SEC_E_DOWNGRADE_DETECTED
I have tried /13/windows and /windowstransport as well as the endpoint.
private static GenericXmlSecurityToken RequestSecurityToken()
{
// set up the ws-trust channel factory
var factory = new Microsoft.IdentityModel.Protocols.WSTrust.WSTrustChannelFactory(new WindowsWSTrustBinding(
SecurityMode.TransportWithMessageCredential), new EndpointAddress(new Uri("https://adfs.domain.in/adfs/services/trust/13/windowsmixed"), EndpointIdentity.CreateSpnIdentity("adfs#domain.in")));
factory.TrustVersion = TrustVersion.WSTrust13;
var rst = new RequestSecurityToken
{
RequestType = RequestTypes.Issue,
KeyType = KeyTypes.Bearer,
AppliesTo = new System.ServiceModel.EndpointAddress(endpoint_address)
};
// request token and return
return factory.CreateChannel().Issue(rst) as GenericXmlSecurityToken;
}
In my case, for some reason, the ADFS was available over VPN but the AD based authentication bits are not happening over VPN. That's why SEC_E_DOWNGRADE_DETECTED is coming. In a regular non VPN environment things are good.
Also, another observation is once SAML token is generated over a regular enterprise network. Subsequent calls to generate the SAML token are going through as expected even on VPN.
So, if you see this error just check if the network you are in is part of the domain (and not public or private network), for SSPI negotiation.

Error trying to Connect to GMail with MailKit

I've got the following code...
var credential = GoogleWebAuthorizationBroker.AuthorizeAsync(new ClientSecrets
{
ClientId = "<< MY CLIENT ID>>",
ClientSecret = "<<MY CLIENT SECRET>>"
},
new[] { "https://www.googleapis.com/auth/gmail.readonly" },
"<<EMAIL ADDRESS>>",
CancellationToken.None,
new FileDataStore("Mail2.Auth.Store")).Result;
using (var client = new ImapClient())
{
// THE CODE FAILS ON THIS NEXT LINE
client.Connect("imap.gmail.com", 993, SecureSocketOptions.SslOnConnect);
client.Authenticate("<<EMAIL ADDRESS>>", credential.Token.AccessToken);
}
When run, the code fails on the indicated like with AuthenticationException: The remote certificate is invalid according to the validation procedure.
I initially thought that is was 'cos the account had 2-step authentication on. So, I set up another account ensuring it just used the regular authentication settings and I got the same error.
I have found a number of posts, here and elsewhere, that deal with this exception but they seem to deal with the issue of working with the SmtpClient() and here, as you can see from the code, I'm getting the error with the ImapClient().
Can anyone suggest what it is that may be the cause of the error? Is it GMail? MailKit? .NET? All of the above?
The problem is that your system does not accept the GMail's SSL certificate.
You can override client.ServerCertificateValidationCallback.
A very simple example of a solution might look like this:
client.ServerCertificateValidationCallback = () => true;
Obviously that means that if anyone ever spoofed imap.gmail.com, your software would get caught in a MITM attack, so that's not ideal.
You'll likely want to match the certificate's thumbprint against a known thumbprint or else add the certificate to your local certificate store and assign a trust level to it.

How would I create a HTTPS request in vala?

I am trying to create a github issue app in vala and need to get the list of issues from https://api.github.com/repos/vmg/redcarpet/issues?state=closed.
I have tried using this example in my code but this is not working for SSL.
https://wiki.gnome.org/Projects/Vala/GIONetworkingSample
I have also tried soup but this seems to have a problem where it can't find its dev headers.
Any help would be much appreciated.
You have to set the tls property to true on the SocketClient object, and
you have to connect to the correct port (443). This works for me:
var client = new SocketClient() { tls = true };
// Or do this (does the same):
// var client = new SocketClient();
// client.tls = true;
var socket = client.connect_to_host (hostname, 443);
If the server you are connecting to are using a self-signed certificate,
you also have to change the TLS validation flags:
client.set_tls_validation_flags (...);
But it's probably easier with Soup, as another commenter pointed out.
God luck. Vala is a sweet language.

Resources