Why doesn't my sslstream get the certificate from a mail server? - c#

From my code below, I should be getting the certificate of the mail server "mailgw.th-nuernberg.de".
That didn't work and I get the error "the handshake failed due to an unexpected packet format" by calling the method "AuthenticateAsClient".
I tried the same code with the mail server "smtp.gmail.com" on port 993. That works and I get the full certificate.
The mail server "mailgw.th-nuernberg.de" exists but I don't know why Google's mail server is working and it isn't.
Here is my Code:
X509Certificate2 cert = null;
var client = new TcpClient("mailgw.th-nuernberg.de", 25);
var certValidation = new RemoteCertificateValidationCallback(delegate (object snd, X509Certificate certificate,
X509Chain chainLocal, SslPolicyErrors sslPolicyErrors)
{
return true; //Accept every certificate, even if it's invalid
});
// Create an SSL stream and takeover client's stream
using (var sslStream = new SslStream(client.GetStream(), true, certValidation))
{
sslStream.AuthenticateAsClient("mailgw.th-nuernberg.de", null, System.Security.Authentication.SslProtocols.Tls13 | System.Security.Authentication.SslProtocols.Tls12 | System.Security.Authentication.SslProtocols.Tls11, true);
var serverCertificate = sslStream.RemoteCertificate;
cert = new X509Certificate2(serverCertificate);
//System.Diagnostics.Debug.WriteLine("Heruntergeladenes Zertifikat: " + cert);
}
}
catch (Exception e)
{
System.Diagnostics.Debug.WriteLine(e.Message);
//throw some fancy exception ;-)
}
Does anyone know what the problem is? What's the difference using the Google mail server instead of using the mail server from my University?

Related

C#, How to get Client's certificate (acquire a client certificate during the TLS handshake process)

My project is a simple server which accepts connection requests on port 5123 also my server use a specific certificate.
If the department of computer science makes a connection request to my server and use any certificate allowed by my server, my server will accept that request and everything will be ok
But if the department of information technology makes a connection request to my server and used a different certificate! my server will force close that connection and throw this error A call to SSPI failed, see inner exception.
I made a function DisplayCertificateInformation which gives you certificate information of client. That function works if the client used any certificate allowed by my server. If the client used a different certificate that function will throw this error "A call to SSPI failed, see inner exception."
Also if client used a different cert my server will abort on this line by throwing this error "A call to SSPI failed, see inner exception." and will ignore the rest lines
ServerSslStream.AuthenticateAsServer(certificate, false, SslProtocols.Tls12, false);
My question is how can I get client's cert when the client try to connect to my server, I just want to know which cert did the client use because I want to add an exception for some department's certificate, not all departments
Here is my code
private static void AcceptConnection_SSL(object client)
{
TcpClient inClient = client as TcpClient;
NetworkStream stream = inClient.GetStream();
SslStream ServerSslStream = new SslStream(inClient.GetStream(), false, SslValidationCallback);
// These two lines will throw error if client used different cert
ServerSslStream.AuthenticateAsServer(certificate, false, SslProtocols.Tls12, false);
DisplayCertificateInformation(ServerSslStream);
}
private static Boolean SslValidationCallback(Object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslpolicyerrors)
{
return true;
}
static void DisplayCertificateInformation(SslStream stream)
{
Console.WriteLine("Certificate revocation list checked: {stream.CheckCertRevocationStatus}");
X509Certificate localCertificate = stream.LocalCertificate;
if (stream.LocalCertificate != null)
{
Console.WriteLine("Local cert was issued to {0} and is valid from {1} until {2}.",
localCertificate.Subject,
localCertificate.GetEffectiveDateString(),
localCertificate.GetExpirationDateString());
}
else
{
Console.WriteLine("Local certificate is null.");
}
// Display the properties of the client's certificate.
X509Certificate remoteCertificate = stream.RemoteCertificate;
if (stream.RemoteCertificate != null)
{
if (remoteCertificate != null)
{
Console.WriteLine(
"Remote cert was issued to {remoteCertificate.Subject} and is valid from {remoteCertificate.GetEffectiveDateString()} until {remoteCertificate.GetExpirationDateString()}.");
}
}
else
{
Console.WriteLine("Remote certificate is null.");
}
}
C#, How to get Client's certificate (acquire a client certificate during the TLS handshake process)

Trying to verify a LDAP over SSL certificate, Server cannot be reached

I'm currently trying to connect to a LDAPS Server using the following VB.NET Code, which should set the right parameters and use the function seen below to verify the certificate when the Bind function is called.
The value of LdapHost is the IP, 10.100.11.10, and the value for LdapPort is 7636.
connection = new LdapConnection(new LdapDirectoryIdentifier(LdapHost, LdapPort));
connection.AuthType = 2; // Negotiate
connection.SessionOptions.SecureSocketLayer = true;
connection.SessionOptions.VerifyServerCertificate = new VerifyServerCertificateCallback(VerifyServerCertificate);
//Both username and password are correct
connection.Credential = new System.Net.NetworkCredential(strUsername, strPassword);
connection.Bind();
This,
But upon trying to verify the Server Certificate, using the following code:
private bool VerifyServerCertificate(LdapConnection ldapConnection, X509Certificate certificate)
{
try
{
X509Certificate2 certificate2 = new X509Certificate2(certificate);
return certificate2.Verify();
}
catch (Exception ex)
{
throw new LdapException(9999, "Invalid certificate or path.");
}
}
It Errors out at the Bind function saying that it cannot connect to the LDAP Server at all with the message "The LDAP Server cannot be reached"
Although upon testing the connection via PowerShell, the Server is available just fine.
Is there something wrong with my verification method? Should I try a different approach entirely?
I have found the reason why the verification did not work.
Using
X509Chain chain = new X509Chain();
X509Certificate2 certificate2 = new X509Certificate2(certificate);
var chainBuilt = chain.Build(certificate2);
LogEvent("Val", 0, "Chain building status: " + chainBuilt);
if (chainBuilt == false) {
foreach (X509ChainStatus chainStatus in chain.ChainStatus)
LogEvent("Val", 0, "Chain error: " + chainStatus.Status + " " + chainStatus.StatusInformation);
chain.Reset();
return false;
} else {
chain.Reset();
return true;
}
if the verification fails helped me understand that the Root Certificate was not trusted on that specific server.
Furthermore, it told me that it could not reach the Revokation Server to check if the Certificate is still valid.
This couldn't be checked though, since the configuration uses a StartTLS certificate, which does not have a Revokation Server.
Therefore, I added
chain.ChainPolicy.VerificationFlags = X509VerificationFlags.IgnoreRootRevocationUnknown | X509VerificationFlags.IgnoreEndRevocationUnknown | X509VerificationFlags.IgnoreCtlSignerRevocationUnknown;
to ignore every property regarding the Revokation Server. It can now connect as intended.

TCP Client C#: The remote certificate is invalid according to the validation procedure

I am trying to establish a communication between a C# client and a C# server through TCP/SSL.
I have generated self signed certificate using IIS and imported it into the trust store.
The communication works well when the client and the server are hosted on the same machine. (I am able to exchange packets).
But when the client is on another machine, I am getting this error : the remote certificate is invalid according to the validation procedure.
I have recreated the certificate. (same error)
public static bool ValidateCertifiate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) {
if (sslPolicyErrors == SslPolicyErrors.None)
return true;
Console.WriteLine("Error: {0}", sslPolicyErrors);
return false;
}
// Main code
public static int Main(string[] args){
TcpClient tcpClient = new TcpClient("IP", 8080);
SslStream stream = new SslStream(tcpClient.GetStream(), false, new RemoteCertificateValidationCallback(ValidateCertifiate), null);
try {
stream.AuthenticateAsClient("CertificateIssuer");
} catch (Exception e) {
Console.WriteLine("Exception: {0}", e.Message);
}
}
I am wondering why the program is working when the client is on the same host of the server and not working when the client is on different machine.
I imported the certificate on the right client trust store. Now the communication is established.
Thanks

EWS C#, Autodiscover URL fails to set on Office365 account

I have successfully managed to run an EWS service on a non Office 365 account,
however, using an internal office 365
public ExchangeService connectToExchange()
{
var ews = new ExchangeService(ExchangeVersion.Exchange2010_SP1)
{Credentials = new WebCredentials(authenticate.ExchangeUsername,
authenticate.ExchangePassword) };
}
try
{
ews.AutodiscoverUrl(authenticate.ExchangeURL);
}
The URL does not get set and when i hardcode a URL, where can we get this from in Office365? When I hardcode the following
url:https://mail.domain.com/EWS/Exchange.asmx");
I get the error that proxy needs to be authenticated, how can one achieve this?
Thanks:
I have managed to get this so far but still get authentication required error, how do i authenticate here?
public ExchangeService connectToExchange()
{
var ews = new ExchangeService(ExchangeVersion.Exchange2010_SP1) {Credentials = new WebCredentials(authenticate.ExchangeUsername, authenticate.ExchangePassword) };
try
{
WebProxy myproxy = new WebProxy("proxyurl", port);
myproxy.BypassProxyOnLocal = false;
myproxy.Credentials = new NetworkCredential("user","pass");
ews.WebProxy = myproxy;
ews.Url = new Uri("exchangeurl");
}
catch
{
}
return ews;
}
Almost there... proxy is correct now, the error is now:
"The request failed. The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel."
You must create a certificate validation callback method for your application. See explanation here.
using System.Security.Cryptography.X509Certificates;
using System.Net.Security;
// Validate the server certificate.
ServicePointManager.ServerCertificateValidationCallback =
delegate(object sender,
X509Certificate certificate,
X509Chain chain,
SslPolicyErrors sslPolicyErrors)
{ return true; };

Connecting to FTPS (FTP over SSL) with FluentFTP

I am using IIS in my local machine for testing FTP with SSL connection. I am using the FluentFTP library for connecting to the FTP. I am using the following code to connect to the Server.
FtpClient conn = new FtpClient();
conn.Host = firewallSslDetails.Address;
conn.Credentials = new NetworkCredential(firewallSslDetails.UserName, firewallSslDetails.Password);
conn.SslProtocols = System.Security.Authentication.SslProtocols.Default;
X509Certificate2 cert = new X509Certificate2(#"C:\Users\BizTalk360\Desktop\FtpSites\ServerCert.cer");
conn.EncryptionMode = FtpEncryptionMode.Implicit;
conn.DataConnectionType = FtpDataConnectionType.AutoActive;
conn.DataConnectionEncryption = true;
conn.EnableThreadSafeDataConnections = false;
conn.ClientCertificates.Add(cert);
conn.ValidateCertificate += new FtpSslValidation(OnValidateCertificate);
conn.Connect();
The server is returning me with the following error.
FluentFTP.FtpCommandException: Policy requires SSL.; Win32 error: Access is denied.; Error details: SSL policy requires SSL for control channel.;
For connecting over FTP the above code is working fine and for FTP with SSL it is not working.
As you seem to be connecting to the default port 21 (no explicit port specified anywhere), you need to use the "Explicit" mode:
conn.EncryptionMode = FtpEncryptionMode.Explicit;
If the server uses a self-signed certificate, you may need to verify it programmatically. Do not blindly accept any certificate, as the answer by #Ivan does. That's a security flaw. Validate the specific certificate, e.g. by checking its fingerprint.
See FtpWebRequest "The remote certificate is invalid according to the validation procedure".
//try this ,
var cl = new FtpClient(Server, Port, User, Password);
cl.EncryptionMode = FtpEncryptionMode.Implicit;
cl.DataConnectionType = FtpDataConnectionType.AutoPassive;
cl.DataConnectionEncryption = true;
cl.SslProtocols = protocol;
cl.ValidateCertificate += new FtpSslValidation(OnValidateCertificate);
var cer = new X509Certificate2(certificate);
cl.ClientCertificates.Add(cer);
System.Net.ServicePointManager.ServerCertificateValidationCallback = ServerCertificateValidationCallback;
client.Connect();
void OnValidateCertificate(FtpClient control, FtpSslValidationEventArgs e)
{
// add logic to test if certificate is valid here
e.Accept = true;
}
private bool ServerCertificateValidationCallback(object sender,
X509Certificate certificate,
X509Chain chain,
SslPolicyErrors sslPolicyErrors)
{
return true;
}

Categories

Resources