Yesterday I wanted to download some content off a website with F#, however unfortunately the certificate of the website was expired.
let result = try let request = "https://somewebsite/with/expired/ssl/certificate/data.json?paramx=1¶my=2" |> WebRequest.Create let response = request.GetResponse () // parse data let parsed = "..." Ok parsed with | ex -> Error ex
If we execute this, then result would be of Error with the following exception:
ex.Message "The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel." ex.InnerException.Message "The remote certificate is invalid according to the validation procedure."
So how do we fix this?
The solution is to set the following code at startup of the application (or at least before the first call):
ServicePointManager.ServerCertificateValidationCallback <- new RemoteCertificateValidationCallback(fun _ _ _ _ -> true)
Notice that you should not do this, because this does not validate the certificate at ALL! Also, this is for ALL calls, if you want to do it on a specific call you need to do make some changes.
First of all, it doesn’t work with
WebRequest.Create, you need to use
WebRequest.CreateHttp, or cast the
HttpWebRequest, as the property we need,
ServerCertificateValidationCallback is not available on
WebRequest, only on
HttpWebRequest. The resulting code looks like this:
let request = "https://somewebsite/with/expired/ssl/certificate/data.json?paramx=1¶my=2" |> WebRequest.CreateHttp request.ServerCertificateValidationCallback <- new RemoteCertificateValidationCallback(fun _ _ _ _ -> true) let response = request.GetResponse ()
Again, don’t do this in production!
If need be, do it on a single
HttpWebRequest, like the last example, and write some code so that you ignore the expiration part, but leave in place the validation part.
Code on Github!