vb Could not establish secure channel for SSL/TLS - vb.net

I am working on a project which I did not write, have inherited, and have an issue that I'm not sure quite how to solve. My background is not in .NET, so please excuse anything that doesn't sound right, as I may not know what the correct terminology should be.
We are using Visual Studio 2008 to compile a project that is running on Windows CE 6.0. We are using the Compact Framework v2.0. The software is running on an Embedded processor in a network (WIFI) connected industrial environment. The main UI is written in VB, and all of the supporting DLLs are written using C#.
Up until now we've only been required to connect to http (non-secure) web addresses for GET requests. We now have a requirement to switch these addresses over to https (secure) for security's sake.
The HttpWebRequest is built/submitted from VB. When I provide the code with the https address, I get the "Could not establish secure channel for SSL/TLS" error that is in the subject.
Here is the code for that request:
Dim myuri As System.Uri = New System.Uri(sUrl)
Dim myHttpwebresponse As HttpWebResponse = Nothing
Dim myhttpwebrequest As HttpWebRequest = CType(WebRequest.Create(myuri), HttpWebRequest)
myhttpwebrequest.KeepAlive = False
myhttpwebrequest.Proxy.Credentials = CredentialCache.DefaultCredentials
myhttpwebrequest.ContentType = "text/xml"
myhttpwebrequest.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
myhttpwebrequest.AllowAutoRedirect = False
myhttpwebrequest.Timeout = 150000
Dim mycred As NetworkCredential = New NetworkCredential(username, password)
Dim myCredentialCache As CredentialCache = New CredentialCache()
myCredentialCache.Add(myuri, "Basic", mycred)
myhttpwebrequest.Credentials = myCredentialCache
myhttpwebrequest.Method = "GET"
myhttpwebrequest.ProtocolVersion = HttpVersion.Version10
ServicePointManager.CertificatePolicy = New AcceptServerNameMismatch
myHttpwebresponse = CType(myhttpwebrequest.GetResponse(), HttpWebResponse)
I have done quite a bit of reading over the last day or so that indicate that the CertificatePolicy is where I can override the ICertificatePolicy classes to essentially validate all SSL requests. Definitely not safe, and not ideal, but I'm not sure of another way to handle these requests.
My class to do this is:
Public Class MyCertificatePolicy
Implements ICertificatePolicy
Public Shared DefaultValidate As Boolean = True
Public Sub trustedCertificatePolicy()
End Sub
Public Function CheckValidationResult(ByVal srvPoint As ServicePoint, _
ByVal cert As X509Certificate, ByVal request As WebRequest, ByVal problem As Integer) _
As Boolean Implements ICertificatePolicy.CheckValidationResult
Return True
End Function
End Class
Unfortunately when the response comes back, it never calls CheckValidationResult(). Thus, no validation and the error.
So my questions...
The "Right" way to do this according to everything that I've read is to use the ServerCertificateValidationCallback. Unfortunately with the version of Compact Framework that we are using (maybe all?) it is not included. Is there something that I'm missing that would cause that function not to get called?
Again, from what I've read, I believe that the Framework that we're running on doesn't support TLS v1.1 or v1.2. Which most current servers are running. Is there a way in VB to get around this?
Is there another Request method that can be used?
Any help or guidance as to where to go from here is greatly appreciated!

You need to install the trusted root certificate on the device(s), that matches the SSL certificate on your server.
Or change the certificate on the server to match one of the Trusted Roots on the device(s). By default, the devices ship with a very small number of trusted CAs, unlike desktop browsers that contain nearly every CA in the world.

Related

Azure Sql Server MFA connection from .NET application

My goal is to allow users to connect to our Azure Sql Server using their Azure Active Directory credentials. I'm trying to follow the steps in this article, but I'm getting an error I can't sort out:
Connect to Azure SQL Database with Azure Multi-Factor Authentication
Below are the appropriate pieces of my code, which I largely copied from the example in the article (except my app is written in VB.NET so I had to translate). It requires the Microsoft.IdentityModel.Clients.ActiveDirectory assembly, which I got from NuGet.
Public Module DB
Private ConnectionProvider As ActiveDirectoryAuthProvider
'Gets run at application start
Public Sub SetProvider()
ConnectionProvider = New ActiveDirectoryAuthProvider
SqlAuthenticationProvider.SetProvider(SqlAuthenticationMethod.ActiveDirectoryInteractive, ConnectionProvider)
End Sub
End Module
'I can't believe Microsoft doesn't just have this as a class that's already been written
Public Class ActiveDirectoryAuthProvider
Inherits SqlAuthenticationProvider
Private ReadOnly _clientId As String = "Our Client ID From The Azure Portal"
Private ReadOnly _redirectUri As New Uri("A Valid URL")
Public Overrides Async Function AcquireTokenAsync(parameters As SqlAuthenticationParameters) As Task(Of SqlAuthenticationToken)
Dim authContext As New AuthenticationContext(parameters.Authority)
authContext.CorrelationId = parameters.ConnectionId
Dim result As AuthenticationResult
Select Case parameters.AuthenticationMethod
Case SqlAuthenticationMethod.ActiveDirectoryInteractive
result = Await authContext.AcquireTokenAsync(parameters.Resource, _clientId, _redirectUri, New PlatformParameters(PromptBehavior.Auto), New UserIdentifier(parameters.UserId, UserIdentifierType.RequiredDisplayableId))
Case SqlAuthenticationMethod.ActiveDirectoryIntegrated
result = Await authContext.AcquireTokenAsync(parameters.Resource, _clientId, New UserCredential())
Case SqlAuthenticationMethod.ActiveDirectoryPassword
result = Await authContext.AcquireTokenAsync(parameters.Resource, _clientId, New UserPasswordCredential(parameters.UserId, parameters.Password))
Case Else
Throw New InvalidOperationException()
End Select
Return New SqlAuthenticationToken(result.AccessToken, result.ExpiresOn)
End Function
Public Overrides Function IsSupported(ByVal authenticationMethod As SqlAuthenticationMethod) As Boolean
Return authenticationMethod = SqlAuthenticationMethod.ActiveDirectoryIntegrated OrElse authenticationMethod = SqlAuthenticationMethod.ActiveDirectoryInteractive OrElse authenticationMethod = SqlAuthenticationMethod.ActiveDirectoryPassword
End Function
End Class
'And finally, I create new connections like this:
New SqlConnection($"Server=tcp:ourserver.database.windows.net,1433;Initial Catalog=OurDatabase;TrustServerCertificate=True;Pooling=False;Encrypt=True;Authentication=""Active Directory Interactive"";User ID={Environment.UserName}#OurDomain.com;")
Using this code, I do get the popup from Azure asking me to sign in when I run SqlConnection.Open. As soon as I've signed in however, I get the following exception:
Microsoft.IdentityModel.Clients.ActiveDirectory.AdalServiceException
AADSTS7000218: The request body must contain the following parameter:
'client_assertion' or 'client_secret'.
Any idea how I can fix that?
So, in digging through every resource I could find, I came across this question:
“error_description”:"AADSTS70002: The request body must contain the following parameter: 'client_secret or client_assertion'
The answer linked above points to the "Redirect URI" registered with the application in Azure as the cause of the issue.
The Microsoft article in my question states: "For this article, any valid value is fine for RedirectUri, because it isn't used here." The example they use is: "https://mywebserver.com/".
Contrary to the quote from Microsoft, the answer I linked above points out that Azure uses the Redirect URI to determine the type of application that is being registered. Changing the URI from my company's website to "https://login.microsoftonline.com/common/oauth2/nativeclient" fixes my problem. That URL is one of the default values Azure lets you pick from. It evidently indicates to Azure that you are registering a native app, not a web app. Once Azure knows this, it seems to stop demanding a "'client_assertion' or 'client_secret'", which I can only assume are things required for web app authentication.
I faced with this problem a bit earlier, spent a lot of time to figure out the problem and the only solution which helped was adding of "https://login.microsoftonline.com/common/oauth2/nativeclient" on "Authentication" tab to "Redirect URIs" like it was mentioned by Keith Stein

DKIM Signing an email using MimeKit in a vb.net project

I'm using MimeKit to send emails and the use of DKIM to sign them has been broached. I've looked at the example on the MimKit site, and googled the terms but found no answers.
Public Shared Sub DkimSign(ByVal message As MimeMessage)
Dim headers = New HeaderId() {HeaderId.From, HeaderId.Subject, HeaderId.Date}
Dim headerAlgorithm = DkimCanonicalizationAlgorithm.Simple
Dim bodyAlgorithm = DkimCanonicalizationAlgorithm.Simple
Dim signer = New DkimSigner("filename", "domain", "selector") With {.SignatureAlgorithm = DkimSignatureAlgorithm.RsaSha1, .AgentOrUserIdentifier = "#eng.example.com"}
message.Prepare(EncodingConstraint.SevenBit)
message.Sign(signer, headers, headerAlgorithm, bodyAlgorithm)
End Sub
When instantiating the signer it requires a filename, domain and selector. If I'm sending an email from "bob#website.com" I would assume that the physical file would be placed on the root of the site and the instantiation would look something like this:
Dim signer = New DkimSigner("dkim.txt", "website.com", "") With {.SignatureAlgorithm = DkimSignatureAlgorithm.RsaSha1, .AgentOrUserIdentifier = "???"}
But not sure the format/reason for the AgentOrUserIdentifier ... can anyone edify me or correct me if my assumptions are wrong?
The fileName parameter is the path to the private key that should be used for signing the message. I'm not sure why you expect it to be at the root of the site or why it would be called dkim.txt, but I can almost guarantee that both assumptions are wrong.
A selector is used by the receiving client to locate the correct public key in the DNS records because it's possible for the same domain to have multiple keys that it uses for signing.
The AgentOrUserIdentifier corresponds to the i= parameter that you find in the DKIM-Signature header and specifies the user or agent that is taking responsibility for the signature.

WordPress Post Scraper visual basic

I need following. I need to scrape posts from mine WordPress blog and show them in VB application. But news must be fresh, when user clicks "Refresh" it gets new content from website. So, posts from first page and link to it.
Any way to do this? Is that even possible?
This is very possible and I will give you three possible solutions.
The first solution is to use Telerik's (free!) Testing Framework http://www.telerik.com/teststudio/testing-framework. It is meant to be used for testing your website for flaws and whatnot but it makes for an excellent scraper. Once you get to know how to use the syntax this is most likely the fastest and easiest solution but it also has the most overhead. It uses browser addons to allow you to "control" Mozilla Firefox, Google Chrome, Apple Safari and Microsoft Internet Explorer. The main disadvantage with this one is that you must install the setup package on all computers that you wish to use this on. If you are only building a simple scraper to get data from your own blog and you will only run this on one machine this is probably the best way to go.
The next scraper I will mention is called Watin and you can get it from http://watin.org/. I personally prefer this one to Telerik's because it only requires a few dlls to be included in your project and once deployed it works great on another machine without having to install any special software. Unfortunately there are a few caveats as well. The big issue is that it hasn't been updated since 2011 so I'm assuming the project is dead, although the website still exists. Because of the lack of updates it officially only supports Internet Explorer 6, 7, 8, 9 and FireFox 2 and 3 (But I can vouch for it working fine in IE 10 + 11 on Windows 7+8). The syntax is a bit more wonky than Teleriks but it should be easy enough to use for what you need it for.
The last option that I can recommend is to use the HttpWebRequest and HttpWebResponse classes built into DotNet and do your scraping manually. I will admit that I still use this approach on occasion. It basically just brings back the source code for a certain url and you have to use string manipulation (or regex if you are good at that) to pull out the information you need. The upside to this one is that it has the least overhead as it requires no extra dlls or installs to work, and it's very fast. I will provide you a sample function that I have used and reused in a number of projects to pull data from the web:
Private Function GetMethod(ByVal sPage As String) As String
Dim req As HttpWebRequest
Dim resp As HttpWebResponse
Dim stw As StreamReader
Dim sReturnString As String = ""
Dim sUserAgent As String = "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"
Try
req = HttpWebRequest.Create(sPage)
req.Method = "GET"
req.AllowAutoRedirect = False
req.UserAgent = sUserAgent
req.Accept = "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5"
req.Headers.Add("Accept-Language", "en-us,en;q=0.5")
req.Headers.Add("Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7")
req.Headers.Add("Keep-Alive", "300")
req.KeepAlive = True
resp = req.GetResponse ' Get the response from the server
If req.HaveResponse Then
resp = req.GetResponse ' Get the response from the server
stw = New StreamReader(resp.GetResponseStream)
sReturnString = stw.ReadToEnd() ' Save the source code of the url into a string
Else
MessageBox.Show("No response received from host " & sPage, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
End If
Catch exc As WebException
MessageBox.Show("Network Error: " & exc.Message.ToString & " Status Code: " & exc.Status.ToString & " from " & sPage, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
Return sReturnString
End Function
Just a note about the sUserAgent variable: You can change this to any user agent you want to emulate. In this case I am using Mozilla Firefox 5 which is obviously super old but I have been using this function for years and haven't needed to update it.

HttpWebRequest runs slowly first time within SQLCLR

When making an HttpWebRequest within a CLR stored procedure (as per the code below), the first invocation after the Sql Server is (re-)started or after a given (but indeterminate) period of time waits for quite a length of time on the GetResponse() method call.
Is there any way to resolve this that doesn't involve a "hack" such as having a Sql Server Agent job running every few minutes to try and ensure that the first "slow" call is made by the Agent and not "real" production code?
function SqlString MakeWebRequest(string address, string parameters, int connectTO)
{
SqlString returnData;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(String.Concat(address.ToString(), "?", parameters.ToString()));
request.Timeout = (int)connectTO;
request.Method = "GET";
using (WebResponse response = request.GetResponse())
{
using (Stream responseStream = response.GetResponseStream())
{
using (StreamReader reader = new StreamReader(responseStream))
{
SqlString responseFromServer = reader.ReadToEnd();
returnData = responseFromServer;
}
}
}
response.Close();
return returnData;
}
(Error handling and other non-critical code has ben removed for brevity)
See also this Sql Server forums thread.
This was a problem for me using HttpWebRequest at first. It's due to the the class looking for a proxy to use. If you set the object's Proxy value to null/Nothing, it'll zip right along.
Looks to me like code signing verification. The MS shipped system dlls are all signed and SQL verifies the signatures at load time. Apparently the certificate revocation list is expired and the certificate verification engine times out retrieving a new list. I have blogged about this problem before Fix slow application startup due to code sign validation and the problem is also described in this Technet article: Certificate Revocation and Status Checking.
The solution is pretty arcane and involves registry editing of the key: HKLM\SOFTWARE\Microsoft\Cryptography\OID\EncodingType 0\CertDllCreateCertificateChainEngine\Config:
ChainUrlRetrievalTimeoutMilliseconds This is each individual CRL check call timeout. If is 0 or not present the default value of 15 seconds is used. Change this timeout to a reasonable value like 200 milliseconds.
ChainRevAccumulativeUrlRetrievalTimeoutMilliseconds This is the aggregate CRL retrieval timeout. If set to 0 or not present the default value of 20 seconds is used. Change this timeout to a value like 500 milliseconds.
There is also a more specific solution for Microsoft signed assemblies (this is from the Biztalk documentation, but applies to any assembly load):
Manually load Microsoft Certificate
Revocation lists
When starting a .NET application, the
.NET Framework will attempt to
download the Certificate Revocation
list (CRL) for any signed assembly. If
your system does not have direct
access to the Internet, or is
restricted from accessing the
Microsoft.com domain, this may delay
startup of BizTalk Server. To avoid
this delay at application startup, you
can use the following steps to
manually download and install the code
signing Certificate Revocation Lists
on your system.
Download the latest CRL updates from
http://crl.microsoft.com/pki/crl/products/CodeSignPCA.crl
and
http://crl.microsoft.com/pki/crl/products/CodeSignPCA2.crl.
Move the CodeSignPCA.crl and CodeSignPCA2.crl files to the isolated
system.
From a command prompt, enter the following command to use the certutil
utility to update the local
certificate store with the CRL
downloaded in step 1:
certutil –addstore CA c:\CodeSignPCA.crl
The CRL files are updated regularly,
so you should consider setting a
reoccurring task of downloading and
installing the CRL updates. To view
the next update time, double-click the
.crl file and view the value of the
Next Update field.
Not sure but if the delay long enough that initial DNS lookups could be the culprit?
( how long is the delay verse a normal call? )
and/or
Is this URI internal to the Network / or a different internal network?
I have seen some weird networking delays from using load balance profiles inside a network that isn't setup right, the firewalls, load-balancers, and other network profiles might be "fighting" the initial connections...
I am not a great networking guy, but you might want to see what an SA has to say about this on serverfault.com as well...
good luck
There is always a delay the first time SQLCLR loads the necessary assemblies.
That should be the case not only for your function MakeWebRequest, but also for any .NET function in the SQLCLR.
HttpWebRequest is part of the System.Net assembly, which is not part of the supported libraries.
I'd recommend using the library System.Web.Services instead to make web service calls from inside the SQLCLR.
I have tested and my first cold run (after SQL service restart) was in 3 seconds (not 30 as yours), all others are in 0 sec.
The code sample I've used to build a DLL:
using System;
using System.Data;
using System.Net;
using System.IO;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
namespace MySQLCLR
{
public static class WebRequests
{
public static void MakeWebRequest(string address, string parameters, int connectTO)
{
string returnData;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(String.Concat(address.ToString(), "?", parameters.ToString()));
request.Timeout = (int)connectTO;
request.Method = "GET";
using (WebResponse response = request.GetResponse())
{
using (Stream responseStream = response.GetResponseStream())
{
using (StreamReader reader = new StreamReader(responseStream))
{
returnData = reader.ReadToEnd();
reader.Close();
}
responseStream.Close();
}
response.Close();
}
SqlDataRecord rec = new SqlDataRecord(new SqlMetaData[] { new SqlMetaData("response", SqlDbType.NVarChar, 10000000) });
rec.SetValue(0, returnData);
SqlContext.Pipe.Send(rec);
}
}
}

VB.NET HTTP LAG! Trying to make an IM client on my own

I have recently developed and finished a software in which works like aim.
But here's the problem, the server worked just fine for local friends because they lived only 25 miles from the server, so it was lag-less.
But when uploaded to a web host, it lags every time it pings the server.
The server is in PHP, so there's no need to buy a dedicated computer for 400$/month more.
Here's the function in which the client constantly calls upon:
Public Function GetPage(ByVal url As String)
Dim WReq As HttpWebRequest
Dim WResp As WebResponse
Dim sr As IO.StreamReader
Try
WReq = WebRequest.Create(url)
WReq.CookieContainer = cookies
WReq.Timeout = "120000"
WResp = WReq.GetResponse()
sr = New IO.StreamReader(WResp.GetResponseStream())
GetPage = sr.ReadToEnd()
WResp.Close()
Return (GetPage)
Catch err As SystemException
MsgBox("err message: " & err.ToString & vbCrLf)
Catch ex As Exception
MsgBox("err message: " & ex.ToString & vbCrLf)
End Try
End Function
A demo url would be something like
http://localhost/chat/newpm.php?to=User&msg=Hello
So how does OSCAR do it (the platform for AOL, aka AIM)
and how does msg? gtalk or other big im clients do it?
I was thinking about recoding the getpage function so that it would connect to a TCP server and constantly wait for new messages which I am still not sure if this might cause a lag if the host is in the US and the client is not(for example).
Could you please provide me a remedy to this problem?
The Timeout is really high. Check if the app closes the connection after receive the response stream. How many aconnections the computer accepts otherwise the connectios will lock the request until one goes free.
Ok to answer John Feminella:
Exactly I agreee, how does AIM MSN and others solve this hang issue?
Dbasnett: return(GetPage) will return the result of the requested page, and this is just the main snipppet of the code which is called every second at least two times.
John Saunders:
I don't understand the purpose or function of the "using" blocks, I added the catch so that the user is not notified when the server times out or can't be resolved.
Sein Kraft:
Time out is only 2 minutes, i don't think it does
GetPage(Login.server & "pms.php?to=" & to)
That's all, then it would parse the results from the response.