How to validate server SSL/TLS certificate against Certificate Revocation List in RabbitMQ .NET Client

I had a need to validate the server certificate that was used by RabbitMQ to ensure it wasn’t revoked. This adds an additional layer of security when communicating with the server and helps ensure you don’t have a man in the middle attack with an unsavory ill-gotten certificate.

Is it really needed, well, that is up to your business needs. I added the ability to do the check in the library itself, but that won’t come out until the next release.

In the mean time, if you need this functionality now, or don’t want the new client, then you simply need to override the server certificate validation callback and implement the following code.

Callback code for validating full certificate chain including CRL

// The following method is invoked by the RemoteCertificateValidationDelegate.
      public static bool ValidateServerCertificate(
            object sender,
            X509Certificate certificate,
            X509Chain chain,
            SslPolicyErrors sslPolicyErrors)
      {
 
          Console.WriteLine("Certificate error: {0}", sslPolicyErrors);
 
          //first gate, if any errors bail immediately. no sense in double check.
          if (sslPolicyErrors != SslPolicyErrors.None)
              return false;
 
          //revalidate for CRL.
 
          var cert = new X509Certificate2(certificate);
          chain.ChainPolicy.RevocationMode = X509RevocationMode.Online;
          chain.ChainPolicy.RevocationFlag = X509RevocationFlag.ExcludeRoot;
          var result = chain.Build(cert);
                 
          if(!result)
              Console.WriteLine("Certificate was revoked.");
          return result;
      }

If you want a full example, here is a class I wrote that demos it.

using RabbitMQ.Client;
using RabbitMQ.Util;
using System;
using System.Diagnostics;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Text;
 
namespace RabbitSSLValidation
{
    public  class RabbitTest:IRabbitTest
    {
        public SslPolicyErrors ErrorsAllowed { getset; }
        public SslPolicyErrors ErrorsFound { getprotected set; } = SslPolicyErrors.None;
 
        public RabbitTest(SslPolicyErrors errorsAllowed)
        {
            ErrorsAllowed = errorsAllowed;
        }
        const string HelloWorldQueue = "HELLO";
 
        public  bool ConnectToServer(string host,string sslHost,string username,string password, string certificate,string certificatePassword)
        {
            var rtn = false;
            var factory = new ConnectionFactory() {
                HostName = host,
                UserName = username,
                Port = 5671,
                Password = password,
                Ssl =new SslOption()
                {
                    Enabled=true,
                    AcceptablePolicyErrors = ErrorsAllowed,
                    ServerName = sslHost,
                    CertificateValidationCallback = ValidateServerCertificate,
                    CertPath = certificate,
                    CertPassphrase = certificatePassword
                }
            };
            using (var connection = factory.CreateConnection())
            using (var channel = connection.CreateModel())
            {
                channel.QueueDeclare(HelloWorldQueue, falsefalsefalsenull);
                channel.BasicPublish("", HelloWorldQueue, nullEncoding.UTF8.GetBytes("Hello, World"));
                BasicGetResult result = channel.BasicGet(HelloWorldQueue, true);
                if (result != null)
                {
                    rtn = true;
                    DebugUtil.DumpProperties(result, Console.Out, 0);
                }
                channel.QueueDelete(HelloWorldQueue);
            }
 
            return rtn;
        }
 
 
        private  bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain,
            SslPolicyErrors sslPolicyErrors)
        {
            ErrorsFound = sslPolicyErrors;
            
            if ((sslPolicyErrors & ~ErrorsAllowed) != SslPolicyErrors.None)
            {
                Debug.WriteLine("Certificate error: {0}", sslPolicyErrors);
                return false;
            }
 
            //check crl ourselves, which actually rechecks the entire thing again in full.
            chain.ChainPolicy.RevocationMode = X509RevocationMode.Online;
            return chain.Build(new X509Certificate2(certificate));
         }
 
    }
 
   
}

Happy coding!

Validate Certificate Revocation List(CRL) with HttpClient in c# .NET

So, you need to make sure the sites you talk to haven’t had their certificates revoked. Well, by default .NET doesn’t do this. Mainly because I think it is rare and it can be slow. Yes yes, caching, blah blah, but the first time and every cache refresh its slower.

Anyway, here is code to handle it.

 

using System;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
 
namespace SecureHTTPDemo
{
    static class Program
    {
        private const string Revokedurl = "https://revoked.badssl.com/";
        private const string ExpiredUrl = "https://expired.badssl.com/";
        private const string SelfSignedUrl = "https://self-signed.badssl.com/";
        private const string UntrustedRootUrl = "https://untrusted-root.badssl.com/";
 
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        public static void Main(string[] args) => Main().GetAwaiter().GetResult();
 
 
        static  async Task Main()
        {
            //check revoked without crl checks.
            await FetchPageSecurelyTest("Revoked", Revokedurl);
            await FetchPageSecurelyTest("Revoked", Revokedurl, true, true);
            //check expired
            await FetchPageSecurelyTest("Expired", ExpiredUrl,false,true);
 
            //check self signed
            await FetchPageSecurelyTest("Self signed", SelfSignedUrl, false, true);
            //check untrusted root
            await FetchPageSecurelyTest("Bad root", UntrustedRootUrl, false, true);
 
            Console.WriteLine("Any key to quit");
            Console.ReadKey();
        }
 
        static async Task FetchPageSecurelyTest(string test, string url, bool enforceCRL = false,
            bool expectException = false)
        {
            var result = await FetchPageSecurely(url, enforceCRL, expectException);
            Console.WriteLine(result ? $"{test} success." : $"{test} was not successful.");
        }
 
        static async Task<bool> FetchPageSecurely( string url,bool enforceCRL = false, bool expectException=false)
        {
            try
            {
                ServicePointManager.CheckCertificateRevocationList = enforceCRL;
                var fetcher = new HttpClient();
                var result = await fetcher.GetStringAsync(url);
                if (expectException) return false;
                var resultValid = !string.IsNullOrEmpty(result);
                return resultValid;
            }
            catch (Exception ex)
            {
                if (expectException) return true;
                Console.WriteLine("Exception unexpected:" + ex.Message);
                return false;
            }
        }
 
    }
 
    public class BriansSecureWebHandler : WebRequestHandler
    {
        public BriansSecureWebHandler()
        {
            
 
        }
    }
}

PrazeMe Q1 2018 Update

Be a better manager, build better employees! PrazeMe is a performance management system for people managers, simplifying the coaching and feedback process so you can concentrate on your core work.

New Features at-a-glance for the Q1 Release

    • Supervisors
    • Assessment Distribution Support for offline or external user scenarios
    • Assessment Naming
    • Reports
    • Enhanced User Experience(UX)

Supervisors (Project leads,etc)

You asked for it, now it’s here. PrazeMe always followed the organization hierarchy of traditional business, but not all businesses are traditional. We have been made aware of a  lot of people who have project workers, so they get assigned to multiple “bosses” and they should all be able to track and share feedback as well as do assessments for the employees.
A common scenario for one employer was workers who changed projects every couple of weeks, they wanted the ability to have each of the project managers write a feedback assessment report after each project and let the new project lead see that information. Now they can. The employee can have an unlimited number of supervisors(still only one direct manager though), which all have access to the employee file.

What the difference between the Manager and the Supervisor?
Simple. Supervisors can see the employees profile, Manager’s can also access all the direct employees of that employee all the way down the tree.


Assessment Distribution

We have customers who have a workforce that works for other customers. Staffing agency scenario is a common one. Now they have two choices for how to handle this situation.

1) Setup the manager at the worksite on their PrazeMe company profile and set them as a supervisor.
or
2) Use the new Assessment Distribution option.

How does this new feature work?
You start an assessment for the employee, then click the Overview link. You can then hit the Print Offline link and get a survey form you can print and send over to the manager for them to fill out. They send it back and you fill in the survey yourself using the information they provided.


Assessment Naming

The existing method for assessment was date based, but we thought we could do better. Now you name the assessment so it is easier to identify. Q1 2018 Quarterly review, or 2018 Contoso Project Assignment Review are much more meaningful than just 03/28/2018.
This feature is for all new assessments you create. We are planning on adding a rename feature later for you to adjust existing assessments. Stay tuned!


Reports

We are in the process of rolling out reports We currently have 3 of them. All reports currently require a Pro license.

  • Employee Feedback Aggregate Report (HR Access only)
    • Allows you to guage all your employees based on past feedback and see if its mostly positive or negative, and then drill into their profile
  • Employee Assessment Score Report (HR Access only)
    • You can quickly see the last 5 assessment scores for all employees to tracking positive or negative trending
  • Feedback that I have created report
    • A report of all the feedback you have created for all employees

Enhanced User Experience

We have been working hard and are still in the process of overhauling the system to be even more user friendly and easy to use. We pride ourselves on being one of the easiest system for people to use. If you have any suggestions or areas in which we can improve, please let us know. Our UX engineers believe the customers need simple and effective software and that is what we strive to deliver.

Some areas you may have noticed are we have moved the Add Feedback, Add Assessment and Add Goal to the top of the employee profile page to make this a quick option since those are the most used features on a daily basis.

We have added sticky panels. When you collapse a panel in the employee profile section, it will remember that on your device and keep those panels the way you want them.

Panel badges. Easily see how many assessments, pieces of feedback, etc there are.

The dashboard has been cleaned up and simplified even more. There are number of other small changes that have been made to enhance the system.


We hope you come check out all the new features!

If you no longer use PrazeMe but would like to check us out again, let us know and we can renew your trial license.

Have a lot of employees? Let us know as we offer price breaks and concierge setup.

New major release of PrazeMe dropped today

PrazeMe, the popular small to medium business employee appraisal and performance management system release a slew of new features in last nights deployment.

You can now custom tailor all your appraisal’s questions, this makes it so you can ensure the topics, questions, and answers are all perfect for your unique business.

Feedback got an upgrade, now you can tag it with positive negative or neutral and it shows as color coded on the employee’s file. Easy to see.

Single location for managing licenses as well as new company administrative functions and organization hierarchy support.

Go check it all out for yourself.

SQL: How to get depth from a recursive cte

If you need to know what level deep you are when recursing through a series of parent child relationships, there is a pretty easy way.

DECLARE @Folders TABLE ( ID INT NOT NULL, FolderTypeLID INT NOT NULL, Depth INT NOT NULL,SortOrder INT NOT NULL );
WITH cteFolder( FolderID,Depth )
AS
(
SELECT @topFolderID,Depth = 0
UNION ALL
SELECT f.ID, Depth +1
FROM Folder f
JOIN cteFolder cte
ON f.ParentID = cte.FolderID
)

 

Happy Coding!

SQL: How to include an incrementing column in your query without a cursor or loop

I had the need to do a recursive call that included depth and sort orders. I wanted to reformat the sort orders in a single query without using a cursor or loop.

Turns out there is an easy way with SQL 2005 or higher.

@Folders is a table var from my CTE with Depth and SortOrder in it.

SELECT ID,(ROW_NUMBER() OVER (ORDER BY f.Depth,f.SortOrder,r.SortOrder)) * 100 as SortOrder
FROM someTable r
JOIN @Folders f
ON r.FolderID = f.ID
ORDER BY SortOrder;

Happy Coding!

How to add a custom user agent in the header using a webview and Xamarin Forms

I am writing an app using Xamarin Forms and wanted to control the user agent for my webview. It’s a little hacky way to have the website render differently when it see that it’s my app coming in without having to use session cookies or other crap like that.

It was pretty easy once I found the code, but finding the code was the pain. Well, Add this renderer to your IOS project.

Snippet

using Foundation;
using PrazeMeApp.iOS.Renderers;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
 
[assembly: ExportRenderer(typeof(WebView), typeof(MyWebViewRenderer))]
namespace PrazeMeApp.iOS.Renderers
{
    public class MyWebViewRenderer : WebViewRenderer
        {
            protected override void OnElementChanged(VisualElementChangedEventArgs e)
            {
            NSDictionary dictionary = NSDictionary.FromObjectAndKey(NSObject.FromObject("myuseragentgoeshere"), NSObject.FromObject("UserAgent"));
            NSUserDefaults.StandardUserDefaults.RegisterDefaults(dictionary);
            base.OnElementChanged(e);
            }
        }
    }

 

Happy Coding!

Xamarin PCL – How to URL Encode since there is no HttpUtility

Looking for the HTTPUtility class? Ha, you don’t get it. PCL doesn’t have it. Fret not, though, you can still URL Encode.

It’s easy, just in a different spot.

How to URLEncode in Xamarin Forms PCL

var encodedData = System.Net.WebUtility.UrlEncode(stuffToEncode);

Now you know, and now hopefully I will remember!

Happy coding!

Where is the Hosts file location in Windows 8?

The Hosts files is a file that allows you to override the DNS lookups for specific domains.

Say you want to test your application that has brianseekford.com hardcoded but you actually want to run it against your local computer IP 127.0.0.1

You edit the hosts file and simply add the entry:

127.0.0.1      brianseekford.com

ALL dns lookups will now return 127.0.0.1 when looking for that domain, so your browsers etc will now all redirect. It was also the old school way to do ad blocking, put in a domain you never want to resolve. i.e. ads.joe.com

Anyway, now that you know what it does, this is where to find it:

C:\Windows\System32\drivers\etc

Remember, open notepad as Administrator FIRST, otherwise you wont be able to save.

 

Temporary fix for internet for Frontier FIOS after Verizon takeover

Did you lose internet access after Fronter screwed the pooch on the Verizon take over? Personally, I am pissed at both Verizon and Frontier. Verizon was doing a fine job but got money hungry for quick capital and sold us to these clowns.

Businesses all over lost internet, phone, etc because they screwed up big time.

Well, it’s possible you might be able to get your internet working again with a little self-help.

I found that two things got me working again, but these are somewhat temporary fixes depending on how bad Frontier messes things up.

  1. You should change your DNS to googles public DNS. This means changing the way your computer/device looks up website names.

i.e. when you type in google.com it has to look up google.com in the DNS system to get the IP address of the website. Then you go to the IP. Frontiers DNS seems to suck a  big nut and not work, so you get a “domain not found” etc error. If you are getting that error, this may resolve your problem.

If you are a somewhat tech: The DNS IP’s are simple. 8.8.8.8 and 8.8.4.4

If you need more help setting it, Here is a link so I don’t have to type it all out:

http://www.howtogeek.com/164981/how-to-switch-to-opendns-or-google-dns-to-speed-up-web-browsing/

 

Now the second thing you will need to do is log in to your router. I hope you remember the credentials. If not, reset the bad boy and use the defaults for your router model. You should be able to look those up.

I use a Verizon ActionTec router.

What you need to do is release and renew the lease on the IP address in your router on the WAN. Sounds complicated right? It isn’t. It’s more complicated getting to the screen.

Here is a link that may help:

http://www.dslreports.com/faq/15898

 

Realistically, just type in your Router model on the back of the router and google How to Release IP Address on X.

 

I wish I could help more, but I am pretty slammed and just wanted to point out there may be a fix. It worked for me. At least my stuff works now, but only the devices I can change the DNS on. I still have to release and renew every few days as well.

 

So, in summary:

Change your DNS to 8.8.8.8 and 8.8.4.4

Release and Renew your IP on your Router.

Ideally, also set the DNS on the router on the WAN and LAN to the IP addresses above as well for devices that automatically use the DHCP supplied 192.168.1.1 IP.

 

-Happy Networking

 

Oh yeah, Frontier SUCKS and they haven’t changed my mind on that.