When should I use SecureSockOptions or useSsl when connecting using Mailkit - c#

I'm confused on how to use the third parameter when setting up smtp with MailKit.
Here is what I have so far:
// *************** SEND EMAIL *******************
using (var client = new MailKit.Net.Smtp.SmtpClient(new ProtocolLogger("smtp.log")))
{
client.SslProtocols = System.Security.Authentication.SslProtocols.Tls12;
//accept all SSL certificates
client.ServerCertificateValidationCallback = (s, c, h, e) => true;
// Note: since we don't have an OAuth2 token, disable
// the XOAUTH2 authentication mechanism.
client.AuthenticationMechanisms.Remove("XOAUTH2");
// client.Connect(emailSettings.SmtpServer, emailSettings.SmtpPort, emailSettings.IsSslEnabled);
client.Connect(emailSettings.SmtpServer, emailSettings.SmtpPort, emailSettings.AuthType);
if (emailSettings.IsAuthenticationRequired)
{
// Note: only needed if the SMTP server requires authentication
client.Authenticate(emailSettings.SmtpUsername, emailSettings.SmtpPassword);
}
if (emailSettings.TimeOut == 0) emailSettings.TimeOut = 10;
client.Timeout = emailSettings.TimeOut * 1000;
client.Send(message);
client.Disconnect(true);
}
My confusion is on this line:
client.Connect(emailSettings.SmtpServer, emailSettings.SmtpPort , true);
I have the option to pass in either true/false or SecureSockOptions.
This is what I have on my form:
I'm not sure I understand how the two different settings affect the sending of emails. I assume I use either the true/false for useSsl or the SecureSockOptions? I'm not sure how these work together.
The options for SecureSockOptions are:
None Auto SslOnConnect StartTls StartTlsWhenAvailable
Do these options negate the need for useSsl?

useSsl is a dumbed-down version of SecureSocketOptions.
When you pass true for useSsl, it maps to SecureSocketOptions.SslOnConnect.
When you pass false for useSsl, it maps to SecureSocketOptions.StartTlsWhenAvailable.

Looking at the mailkit documentation Connect method has 5 different signatures (different parameters)
In the case of passing boolean to the Connect it means use ssl if true and don't use ssl if false. There is no method that accepts both the boolean and SecureSocketOptions.
http://www.mimekit.net/docs/html/Overload_MailKit_Net_Smtp_SmtpClient_Connect.htm
You should read up their documentation on the link above.
Also this might be useful from their documentation:
The useSsl argument only controls whether or not the client makes an
SSL-wrapped connection. In other words, even if the useSsl parameter
is false, SSL/TLS may still be used if the mail server supports the
STARTTLS extension.
To disable all use of SSL/TLS, use the Connect(String, Int32,
SecureSocketOptions, CancellationToken) overload with a value of
SecureSocketOptions.None instead.

You should use it when you have a trusted internal network Domain Controller type or trusted box also, when you are securing transmissions (no eavesdrop) and by default most mail servers use it even if you code it in and it reads false you may have a system wrap, which is when the system itself overrides it due to the OSI Model lower levels. I would recommend personally using it when you can it solves a couple of the older transmission model drops on syn ack hand requests and has a higher requested time out value if I remember correctly.

Related

The client has been disconnected while trying to perform the connection

When trying to connect to a Mosquitto MQTT queue running locally, I get the following error.
Unhandled exception. System.AggregateException: One or more errors occurred. (The client has been disconnected while trying to perform the connection)
---> System.Net.Mqtt.MqttClientException: The client has been disconnected while trying to perform the connection
at System.Net.Mqtt.Sdk.MqttClientImpl.ConnectAsync(MqttClientCredentials credentials, MqttLastWill will, Boolean cleanSession)
I am using the default options when setting up the System.Net.Mqtt.MqttClient.
var config = new MqttConfiguration() {
Port = 1883
};
var client = MqttClient.CreateAsync("localhost", config).Result;
var sessionState = client.ConnectAsync(
new MqttClientCredentials(clientId: "camerasim")).Result;
The following errors show up in the Mosquitto MQTT log.
1644497589: New connection from 172.17.0.1:56792 on port 1883.
1644497589: New client connected from 172.17.0.1:56792 as camerasim (p2, c0, k0).
1644497589: Bad socket read/write on client camerasim: Invalid arguments provided.
The error you are seeing is most likely the result of a change made in Mosquitto 2.0.12:
Fix max_keepalive not applying to MQTT v3.1.1 and v3.1 connections. These clients are now rejected if their keepalive value exceeds max_keepalive. This option allows CVE-2020-13849, which is for the MQTT v3.1.1 protocol itself rather than an implementation, to be addressed.
A change made in 2.0.9 also comes into play:
Fix max_keepalive option not applying to clients connecting with keepalive set to 0. Closes #2117.
These changes were made to address an issue with the MQTT protocol itself which permits a denial of service attack (CVE-2020-13849).
The default value for max_keepalive is 65535 so this change means that attempting to connect with keep alive set to 0 (meaning no keepalive) will fail unless mosquitto.conf specifies max_keepalive 0. Unfortunately the error logged (Bad socket read/write on client XXXXXYYYYY: Invalid arguments provided.) does not really highlight the cause.
There are two available solutions:
Specify max_keepalive 0 in mosquitto.conf (Mosquitto 2.0.13 or later).
When connecting specify a keep alive between 1 and 65535. In xamarin/mqtt this means adding KeepAliveSecs to your config; this defaults to 0.
Note that setting KeepAliveSecs = 1 (as per your answer) will allow you to connect but is probably a little short for most users (KeepAliveSecs = 60 may be more appropriate). e.g.
var configuration = new MqttConfiguration {
Port = 1883,
KeepAliveSecs = 60,
WaitTimeoutSecs = 2,
};
I realise that you have already found a solution to this but as it's likely to affect others I thought it was worth explaining the root cause of the issue. Many MQTT libraries default keep alive to 0 so will be impacted (e.g. Go Paho had an issue logged).
I was able to successfully make a connection by changing the default KeepAliveSecs property when setting up the MqttConfiguration.
var config = new MqttConfiguration() {
KeepAliveSecs = 1,
Port = 1883
};

Docusign C# CreateEnvelope error - Could not establish trust relationship for the SSL/TLS secure channel

After the go live process, I created the new keys and I am using them as well. But I got this error
Error calling CreateEnvelope: The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel.
I am using a c# application. The exception is thrown in the Create Envelope method:
EnvelopeDefinition Envelope = new EnvelopeDefinition
{
EmailSubject = EmailSubject,
Documents = EnvelopeDocuments,
Recipients = new Recipients { Signers = Signers },
Status = "sent"
};
return GetEnvelopesApi().CreateEnvelope(_AccountId, Envelope).EnvelopeId;
Where GetEnvelopesApi just call the public EnvelopesApi(Configuration configuration = null); of docusign.esign.api :
private EnvelopesApi GetEnvelopesApi()
{
ApiClient Client = new ApiClient("https://docusign.net/restapi");
Client.Configuration.AddDefaultHeader("Authorization", "Bearer " + GetAccessToken());
return new EnvelopesApi(Client.Configuration);
}
If I use my developer demo keys instead of the production ones, and "https://demo.docusign.net/restapi" instead of the production url, it works.
What you did to get to the error message
{"errorCode":"USER_LACKS_MEMBERSHIP",
"message": "The UserID does not have a valid membership in this Account."}
was correct.
Next, you need to solve the problem that causes the USER_LACKS_MEMBERSHIP error. It is probably due to you continuing to use a UserId (guid format) from the developer (demo) account. You need to use a UserId from your production account.
Also note that you must determine what the base url is for your account. That determines if you should use www.docusign.net in production, or na2.docusign.net or something else.
You can determine the base url for your account manually or automatically. But it must be correct... Ask another question if you need help on that subject.
The problem you have is the lack of https, so you need to change the url to https://docusign.net/restapi
UPDATE
I think I found your issue! The url should be https://www.docusign.net/restapi due to the fact the ssl certificate is signed to use www. and gives you a certificate error when you don't have it
UPDATE 2
Add the following line before to make the connection:
System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
That is in order to force the connection to use TLS 1.2
Also, I would suggest you to debug it inside the function so you know where it breaks within it
UPDATE 3
In case you still receive the SSL/TLS issue, you could try to add the following line before your rest call too:
ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;

ASP.Net MVC application Defaults to TLS 1.0

We have an ASP.Net MVC application that uses server-to-server communication for retrieving some info.
When we run an installation in the AWS cloud, the request fails because, by default, WebRequest uses TLS 1.0, which we have disabled on our environment. Using the same code in another project defaults to TLS 1.2. Also, hardcoding the protocol in the ServicePointManager fixes the issue.
Does anyone have experience with a similar problem and the underlying cause? I would like to fix this without hardcoding the protocol because it is not future-proof.
I had a similar problem, and ended up simply making it a configuration setting:
//read setting as comma-separated string from wherever you want to store settings
//e.g. "SSL3, TLS, TLS11, TLS12"
string tlsSetting = GetSetting('tlsSettings')
//by default, support whatever mix of protocols you want..
var tlsProtocols = SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
if (!string.IsNullOrEmpty(tlsSetting))
{
//we have an explicit setting, So initially set no protocols whatsoever.
SecurityProtocolType selOpts = (SecurityProtocolType)0;
//separate the comma-separated list of protocols in the setting.
var settings = tlsSetting.Split(new[] { ',' });
//iterate over the list, and see if any parse directly into the available
//SecurityProtocolType enum values.
foreach (var s in settings)
{
if (Enum.TryParse<SecurityProtocolType>(s.Trim(), true, out var tmpEnum))
{
//It seems we want this protocol. Add it to the flags enum setting
// (bitwise or)
selOpts = selOpts | tmpEnum;
}
}
//if we've allowed any protocols, override our default set earlier.
if ((int)selOpts != 0)
{
tlsProtocols = selOpts;
}
}
//now set ServicePointManager directly to use our protocols:
ServicePointManager.SecurityProtocol = tlsProtocols;
This way, you can enable/disable specific protocols, and if any values are added or removed to the enum definition, you won't even need to re-visit the code.
Obviously a comma-separated list of things that map to an enum is a little unfriendly as a setting, but you could set up some sort of mapping or whatever if you like of course... it suited our needs fine.

Easy and reasonable secure way to identify a specific network

We like to enable some hidden features of our software only if it is run inside of the company network. The key requirements are:
no need for a third party library outside of DotNet 4.5.1
easy to implement (should not be more than some dozens of lines .. I don't want to reimplement a crypto library)
It should be reasonable safe:
at least: hard to reverse engineer
at best: "impossible" to break even with read-access to the source code
low maintenance overhead
Win2012-Server is available for installation of additional software (open source or own implementation prefered - server can be assumed to be safe)
What I have thought about:
Check if a specific PC is available with a known MAC or IP (current implementation, not really secure and some other flaws)
Test, if a service is available on a specific response (i.e. I send 'Hello' to MyServer:12345 - server responses with 'World')
Similar to 2nd but a more complex challenge (i.e. send a seed for a RNG to the server, verify the response)
Set up an apache with HTTPS and verify the certificate
If you use ActiveDirectory, you could add a reference to the System.DirectoryServices namespace and check
ActiveDirectorySite currentSite = ActiveDirectorySite.GetComputerSite();
then you can get a bit of information from the currentSite object and check against that. That's how I enable/disable features of an application I'm developing currently.
I also grab:
var client = Dns.GetHostEntry(Dns.GetHostName());
foreach (var ip in client.AddressList)
{
if(ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
{
ipAddress = ip;
}
}
Which you can check to make sure the client is connected with the proper protocol.
I've choosen the last option: Set up a webserver in the intranet and verify the certificate.
It was easier than expected. There are enough tutorials for setting up an apache with https for every supported OS. The self-signed certificate have a lifetime of 9999 days - should be okay until 2042. The C#-part is also reasonable small:
private static bool m_isHomeLocation = false;
public static bool IsHomeLocation
{
get
{
if (m_isHomeLocation)
return true;
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://yourLicenseServer:yourConfiguredPort");
request.ServerCertificateValidationCallback += ((s, certificate, chain, sslPolicyErrors) => true);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
response.Close();
var thumbprint = new X509Certificate2(request.ServicePoint.Certificate).Thumbprint;
m_isHomeLocation = (thumbprint == "WhateverThumbprintYourCertificateHave");
}
catch
{
// pass - maybe next time
}
return m_isHomeLocation;
}
}

How do I resolve a OpenPop.Net Authenticate Exception

I am using OpenPop.Net to connect to a GoDaddy hosted email account in a C# application. The Authenticate() method throws an exception with the error message of "The stream used to retrieve responses from was closed". I doubled checked that the POPServer, POPPort, POPUserName, and POPPassword values were valid using Outlook 2007.
using (Pop3Client pop3 = new Pop3Client())
{
pop3.Connect(POPServer, POPPort, false);
pop3.Authenticate(POPUserName, POPPassword);
Int32 messageCount = pop3.GetMessageCount();
}
The Authenticate() method supports a 3rd parameter, an enumeration called AuthenticationMethod. According to the help file, if the 3rd parameter is not passed the Authenticate() method defaults to an authentication method of Auto. The help file goes on to say that the Auto method is the recommended method to authenticate with. If Apop is supported by the server, Apop is used for authentication. If Apop is not supported, Auto will fall back to UsernameAndPassword authentication.
I tried explicitly passing Auto, and the Authenticate() method failed with the same error. I then tried explicitly passing UsernameAndPassword, this time it worked. I'm not sure if this is a bug in OpenPop.Net or a problem with the POP server. Here is the working code.
using (Pop3Client pop3 = new Pop3Client())
{
pop3.Connect(POPServer, POPPort, false);
pop3.Authenticate(POPUserName, POPPassword, AuthenticationMethod.UsernameAndPassword);
Int32 messageCount = pop3.GetMessageCount();
}

Categories

Resources