Showing posts with label SSL/TLS. Show all posts
Showing posts with label SSL/TLS. Show all posts

Monday, 3 December 2012

SSL Mutual (Two-way) Authentication for WCF services in IIS 7.5 using client certificates

In a previous post, I described  how to configure SSL client Authentication in IIS 7.5 using a One-to-One Mapping.

In this post I describe how to set up a client authenticated WCF web service.

Firstly, there are three pre-requisites.
  1. Server Certificate from trusted CA.
  2. Client Certificate from trusted CA.
  3. WCF service deployed to a website that has been configured to use SSL, see this post for details on how to configure a website to use SSL.
I would suggest following my excellent series on CAs, which starts here, but alas it's mostly oriented for IIS 6, so it's not exactly terribly useful, it does create a CA which is the basis but not much more. Similarly, this post details the usage of makecert to create self-signed certificates but again it's geared towards IIS 6, the certificate generation commands will work though. You can also use openSSL, details here to create self-signed certificates.

In any case, the first step is to ensure that the website is set to require SSL and client certificates:


The second step is to enable Anonymous Authentication. This might sound like a bad idea and to a certain extent it is, using a one to one mapping is a better idea, but I've not got that working yet. What is achieved with this configuration is that any user that has a client certificate from a trusted CA will be be able to use the WCF service.



Third step is to change the configuration file of the WCF service to this (Use your own name and Contract):

  <system.serviceModel>
    <bindings>
      <wsHttpBinding>
        <binding name="TransportSecurity">
          <security mode="Transport">
            <transport clientCredentialType="Certificate"/>
          </security>
        </binding>
      </wsHttpBinding>
    </bindings>
    <services>
      <service name="API.Service" behaviorConfiguration="behaviour">
        <endpoint name="AnEndPoint" address="" binding="wsHttpBinding"
               contract="API.IService"  bindingConfiguration="TransportSecurity">
        </endpoint>
       </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="behaviour">
          <serviceMetadata   httpsGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="true" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>

And finally the client that consumes the web service needs to have this on the configuration file:

<system.serviceModel> 
 <bindings> 
  <wsHttpBinding> 
  <binding name="TransportSecurity"> 
   <security mode="Transport"> 
    <transport clientCredentialType="Certificate" /> 
   </security> 
  </binding> 
  </wsHttpBinding> 
 </bindings> 
 <client> 
  <endpoint address="https://fqdn/service.svc" behaviorConfiguration="behaviour" 
  binding="wsHttpBinding" bindingConfiguration="TransportSecurity" 
  contract="API.IService" name="TransportSecurity" /> 
 </client> 
 <behaviors> 
  <endpointBehaviors> 
   <behavior name="behaviour"> 
    <clientCredentials> 
     <clientCertificate findValue="577aeb8b603af8453b80c55e9ac4abdfd4cf9c6c" 
     storeLocation="CurrentUser" x509FindType="FindByThumbprint" />
    </clientCredentials> 
   </behavior> 
  </endpointBehaviors> 
 </behaviors> 
</system.serviceModel>

Note that you can also use a browser to test this.

Monday, 19 November 2012

Dev tool to configure One to One Client Certificate Mappings in IIS 7.5

In my last post, I described a rather tedious and error prone method for configuring One To One client certificate mappings in IIS 7.5, so with a little bit of help I created a small WPF application that should ensure the smooth configuration of one to one client certificate mappings.

There is no validation as this is simply a developer tool and I'm too lazy to add it, you can have a look at this post for an example of textbox validation in WPF.

Xaml
<Window x:Class="IISCERTTOOL.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        Title="MainWindow" Height="302" Width="477">

    <Grid>
        <Button Content="Add One to One Certificate Mapping" Height="23" HorizontalAlignment="Left" Margin="242,212,0,0" Name="Add" VerticalAlignment="Top" Width="191" Click="Add_Click" />
        <Label Content="UserName" Height="28" HorizontalAlignment="Left" Margin="46,50,0,0" Name="label1" VerticalAlignment="Top" Width="81" />
        <TextBox Height="23" HorizontalAlignment="Left" Margin="163,50,0,0" Name="UserName" VerticalAlignment="Top" Width="241" />
        <Label Content="Password" Height="28" HorizontalAlignment="Left" Margin="46,84,0,0" Name="label2" VerticalAlignment="Top" Width="81" />
        <PasswordBox Height="23" HorizontalAlignment="Left" Margin="163,89,0,0" Name="Password" VerticalAlignment="Top" Width="241" />
        <Label Content="Certificate" Height="28" HorizontalAlignment="Left" Margin="46,118,0,0" Name="label3" VerticalAlignment="Top" Width="81" />
        <TextBox Height="23" HorizontalAlignment="Left" Margin="163,123,0,0" Name="Certificate" VerticalAlignment="Top" Width="241" />
        <Label Content="WebSite" Height="28" HorizontalAlignment="Left" Margin="46,152,0,0" Name="label4" VerticalAlignment="Top" Width="81" />
        <ComboBox Height="23" HorizontalAlignment="Left" Margin="163,152,0,0" Name="WebSite" VerticalAlignment="Top" Width="241" />
        <Button Content="..." Height="20" HorizontalAlignment="Left" Margin="416,123,0,0" Name="SelectCertificate" VerticalAlignment="Top" Width="17" FontStyle="Normal" Click="SelectCertificate_Click" />
    </Grid>
</Window>

Code behind.
 using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 using System.Windows;
 using System.Windows.Controls;
 using System.Windows.Data;
 using System.Windows.Documents;
 using System.Windows.Input;
 using System.Windows.Media;
 using System.Windows.Media.Imaging;
 using System.Windows.Navigation;
 using System.Windows.Shapes;
 using Microsoft.Web.Administration;
 using System.IO;
 using System.Diagnostics;
 
 
 namespace IISCERTTOOL
 {
     /// <summary>
     /// Interaction logic for MainWindow.xaml
     /// </summary>
     public partial class MainWindow : Window
     {
         public MainWindow()
         {
             InitializeComponent();
 
             LoadWebSites();
         }
 
         private void SelectCertificate_Click(object sender, RoutedEventArgs e)
         {
             try
             {
                 Microsoft.Win32.OpenFileDialog dialog = new Microsoft.Win32.OpenFileDialog();
 
                 dialog.AddExtension = true;
                 dialog.CheckFileExists = true;
                 dialog.Filter = "cer files (*.cer)|*.cer";
                 dialog.Multiselect = false;
 
                 if ((bool)dialog.ShowDialog())
                 {
                     Certificate.Text = dialog.FileName;
                 }
             }
             catch (Exception ex)
             {
                 DisplayException(ex);
             }
 
         }
 
         private void Add_Click(object sender, RoutedEventArgs e)
         {
             try
             {
                 string publicKey = ReadKey(Certificate.Text.Trim());
 
                 if (!string.IsNullOrEmpty(publicKey) && ConfigureOneToOneCertMapping(UserName.Text.Trim(), Password.Password.Trim(), publicKey, WebSite.SelectedValue.ToString()))
                 {
                     MessageBox.Show("One to One Mapping successfully added");
                 }
                 else
                 {
                     MessageBox.Show("One to One Mapping was not added");
                 }
             }
             catch (Exception ex)
             {
                 DisplayException(ex);
             }
         }
         /// <summary>
         /// Read certificate file into a string
         /// </summary>
         private string ReadKey(string path)
         {
             StringBuilder publicKey = new StringBuilder();
 
             try
             {
                 string[] file = File.ReadAllLines(path).Skip(1).ToArray();
 
                 for (int i = 0; i < file.Length - 1; i++)
                 {
                     publicKey.Append(file[i]);
                 }
             }
             catch (Exception ex)
             {
                 DisplayException(ex);
             }
 
             return publicKey.ToString();
         }
 
         /// <summary>
         /// Grab all Websites on the server and populate the dropdown combobox.
         /// </summary>
         private void LoadWebSites()
         {
             try
             {
                 List<string> sites = new List<string>();
 
                 using (ServerManager serverManager = new ServerManager())
                 {
                     foreach (Site s in serverManager.Sites)
                     {
                         sites.Add(s.Name);
                     }
                 }
 
                 WebSite.ItemsSource = sites;
             }
             catch (Exception ex)
             {
                 DisplayException(ex);
             }
 
         }
 
         /// <summary>
         /// Configure OneToOne Certificate Mapping for client authenticated SSL/TLS
         /// </summary>
         private bool ConfigureOneToOneCertMapping(string UserName, string Password, string PublicKey, string WebSiteName)
         {
             bool result = false;
 
             using (ServerManager serverManager = new ServerManager())
             {
                 try
                 {
                     Configuration config = serverManager.GetApplicationHostConfiguration();
 
                     ConfigurationSection iisClientCertificateMappingAuthenticationSection = config.GetSection("system.webServer/security/authentication/iisClientCertificateMappingAuthentication", WebSiteName);
                     iisClientCertificateMappingAuthenticationSection["enabled"] = true;
                     iisClientCertificateMappingAuthenticationSection["oneToOneCertificateMappingsEnabled"] = true;
 
                     ConfigurationElementCollection oneToOneMappingsCollection = iisClientCertificateMappingAuthenticationSection.GetCollection("oneToOneMappings");
                     ConfigurationElement addElement = oneToOneMappingsCollection.CreateElement("add");
                     addElement["enabled"] = true;
                     addElement["userName"] = UserName;
                     addElement["password"] = Password;
                     addElement["certificate"] = PublicKey;
                     oneToOneMappingsCollection.Add(addElement);
 
                     ConfigurationSection accessSection = config.GetSection("system.webServer/security/access", WebSiteName);
                     accessSection["sslFlags"] = @"Ssl, SslNegotiateCert";
 
                     serverManager.CommitChanges();
 
                     result = true;
                 }
                 catch (Exception ex)
                 {
                     DisplayException(ex);
                 }
 
                 return result;
 
             }
 
         }
 
         /// <summary>
         /// Gets details of exception and displays them in a textbox.
         /// </summary>
         private static void DisplayException(Exception ex)
         {
             StringBuilder sb = new StringBuilder();
 
             StackTrace trace = new StackTrace();
 
             sb.AppendLine("Exception Occurred.");
 
             sb.AppendLine(string.Format("{0}.{1}",
                 trace.GetFrame(1).GetMethod().ReflectedType.Name, trace.GetFrame(1).GetMethod().Name));
 
 
             sb.AppendLine(string.Format("Source: {0}.", ex.Source));
             sb.AppendLine(string.Format("Type: {0}.", ex.GetType()));
             sb.AppendLine(string.Format("Message: {0}.", ex.Message));
 
             if (ex.InnerException != null)
             {
                 sb.AppendLine(string.Format("Inner Exception: {0}.", ex.InnerException.Message));
             }
 
             MessageBox.Show(sb.ToString());
         }
     }
 }

Saturday, 17 November 2012

Configure SSL Mutual (Two-way) Authentication in IIS 7.5 using client certificates (One-to-One Mapping)

I do know that it's not possible to have SSL mutual authentication without using client certificates, but I thought that I'd throw as many  definitions as possible in a shameless effort to gain more traffic from Google.
At any rate, in this post I discuss how to set up mutual authentication, two-way authentication or SSL with client certificates, whichever way you call it, for the record in Wikepedia it's termed client-authenticated handshake, so I guess it should be a called client authenticated SSL.

Firstly, there are a couple of pre-requisites.
  1. Server Certificate from a trusted CA.
  2. Client Certificate from a trusted CA.
I would suggest following my excellent series on CAs, which starts here, but alas it's mostly oriented for IIS 6, so it's not exactly terribly useful, it does create a CA which is the basis but not much more. Similarly, this post details the usage of makecert to create self-signed certificates but again it's geared towards IIS 6, the certificate generation commands will work though. You can also use openSSL, details here to create self-signed certificates.

I going to assume that the server certificate has already been installed on the server and assigned to a website, see this post for details.

The first thing to do is to navigate to the configuration editor form IIS Manager (This can be invoked by running inetmgr)
Select system.webServer/security/authentication/iisClientCertificateMappingAuthentication.
Now is when things get a little bit strange. Click on the ellipsis button to be presented  with this screen.
     
The very long sequence of letters is the base64 representation of the client certificate and the simplest way of obtaining this is to export the client certificate as base64 certificate (.cer) and then copy the contents of the file.
So that from this "certificate":
-----BEGIN CERTIFICATE-----
MIIFcjCCBVVgVwIBVgIKG4kc/QVVVVVVNzVNBgkqckiG9w0BVQUFVDBCMRMwEQYK
CZImiZPyLGQBGRYDY29tMRMwEQYKCZImiZPyLGQBGRYDZGV2MRYwFVYDVQQDEw1U
-----END CERTIFICATE-----
The following would need to be pasted. It is imperative that this is in one line.
MIIFcjCCBVVgVwIBVgIKG4kc/QVVVVVVNzVNBgkqckiG9w0BVQUFVDBCMRMwEQYK
CZImiZPyLGQBGRYDY29tMRMwEQYKCZImiZPyLGQBGRYDZGV2MRYwFVYDVQQDEw1U
The username and password are the credentials that will be used when the client certificate is used to authenticate, if using a domain account remember to include the domain e.g. test\testaccount 

Finally, ensure that you set the correct SSL Settings are set for the website.


This should ensure that only SSL Client Authenticated access is allowed to the server.

I must say that I'm a bit disappointed by the whole process, it's bad enough to have to play about with the actual certificate itself in all its base 64 glory, but what the fuxx0r Microsoft, passwords in the clear???

This is doubly annoying because, it's not stored in clear text in the configuration file (C:\Windows\System32\inetsrv\config\applicationHost.config), in this file it's encrypted with AES, so why show in the clear from the GUI?

Not entirely sure why this has been changed  from IIS 6, but this just goes to show that higher software versions are not always better, see this post to see how IIS 6 did not have any of this rubbish.

Tuesday, 24 January 2012

Installing secure phpMyAdmin on CentOS 6.2

Following on from Sunday's post on how to set up phpMyAdmin on CentOS 6.2, I thought it would be a good idea to set up phpMyAdmin as a secure website (HTTPS), rather than in clear-text (HTTP). This will ensure that all traffic between the web browser and phpMyAdmin is encrypted.

In a previous post I set up a Certification Authority so I will be using this CA to generate the necessary certificates, but don't worry if you don't have one, you can use makecert or OpenSSL to generate a self signed certificate.

All that is needed is a server and CA certificate, if you've followed my previous post on phpMyAdmin, you can go directly to step 7. Thus armed with a pkcs#12 server certificate (phpMyAdmin.pfx) and a CA certificate (win2kca.cer) we can start:
  1. Set SELinux to allow Apache to bind to a non-default port:
    setsebool -P allow_ypbind 1
  2. Download EPEL Release to enable usage of EPEL Repository: 
    wget http://download.fedora.redhat.com/pub/epel/6/i386/epel-release-6-5.noarch.rpm
  3. Install EPEL Release package:
    yum install epel-release-6-5.noarch.rpm -y
  4. Install phpMyAdmin:
    yum install phpmyadmin -y
  5. Create new directory to host the phpMyAdmin website: 
    mkdir /var/www/phpMyAdmin
  6. Copy phpMyAdmin installation to the directory created in the previous step: 
    cp -r /usr/share/phpMyAdmin/. /var/www/phpMyAdmin
  7. Extract public and private key from server certificate:
    openssl pkcs12 -in phpMyAdmin.pfx -out phpMyAdmin.key -nodes -nocerts
    openssl pkcs12 -in phpMyAdmin.pfx -out phpMyAdmin.crt -nodes -nokeys
  8. Restrict permissions on key file:
    chmod 400 phpMyAdmin.key
  9. Create certificate and key directories and move certificates and keys to them:
    mkdir /etc/httpd/conf.d/certs
    mkdir /etc/httpd/conf.d/keys
    mv phpMyAdmin.crt /etc/httpd/conf.d/certs
    mv phpMyAdmin.key /etc/httpd/conf.d/keys
    cp win2k8ca.cer /etc/httpd/conf.d/certs
  10. Set SELinux to permissive, this is to prevent issues with SELinux preventing Apache from working properly:
    setenforce 0
  11. Edit Apache's SSL configuration file (/etc/httpd/conf.d/ssl.conf). I have changed the port to 7777 and prevented LOW ciphers from being accepted. The rest is simply providing the location of the certificates. Only listing relevant parts of ssl.conf:
    Listen 7777

    <VirtualHost _default_:7777>

    #   SSL Cipher Suite:
    SSLCipherSuite ALL:!ADH:!EXPORT:!SSLv2:RC4+RSA:+HIGH:+MEDIUM

    #   Server Certificate:

    SSLCertificateFile /etc/httpd/conf.d/certs/phpMyAdmin.crt

    #   Server Private Key:

    SSLCertificateKeyFile /etc/httpd/conf.d/certs/phpMyAdmin.key

    #   Server Certificate Chain:
    SSLCertificateChainFile /etc/httpd/conf.d/certs/win2k8ca.cer

    #   Certificate Authority (CA):
    SSLCACertificateFile /etc/httpd/conf.d/certs/win2k8ca.cer

    </VirtualHost>
    1. You can check that the apache configuration file is correct by using:
      apachectl -t 
  12. Restart Apache:
    apachectl -k restart or service httpd restart
  13. Open firewall for port 7777 and save IPTables configuration:
    iptables -I INPUT -p tcp --dport 7777 -j ACCEPT; service iptables save
  14. You can now navigate to https://phpmyadmin.dev.com:7777/setup (If you are using Chrome, you will see this screen first. Other browsers will show similar screens). Note that you'll need a entry on your hosts file that points phpmyadmin.dev.com to the IP address of the Server: 
  15. Click Procceed anyway. You are seeing this because your CA is not trusted by Chrome.
    Although it would seem that the connection is not encrypted, the icon is misleading, it just means that it is not trusted. See below for confirmation:
  16. Because I'm lazy, I'm going to reuse the screenshots and text from my previous phpMyAdmin post, so .. Click New Server. I only changed the name and compression, accepted defaults for everything else:
  17. Go To Authentication Tab. See this link for an overview of the authentication types:
  18. Click Save, which will bring you to the screen below:
  19. Download the configuration file (config.inc.php) and copy it to /var/www/phpMyAdmin.
  20. You can now start using phpMyAdmin on https://phpmyadmin.dev.com:7777:
  21. All that remains is to renable SELinux and deal with the policy violations:
    cat /var/log/audit/audit.log | grep denied > ssl
    audit2allow -M apachessl -i ssl
    semodule -i apachessl.pp
    setenforce 1
Note that steps 2 & 3 simply add repository for the EPEL repository to your yum repository collection and install the repository key.

In theory, the setup script should be able to generate the configuration file for you, but I've not been able to get it to work. Instructions can be found here if you are interested. 

I haven't thoroughly tested this setup so it is possible, as always, that there could be SELinux issues. All I can suggest is that, if you have some inexplicable issue, have a look at the SELinux log (/var/log/audit/audit.log).

    Thursday, 15 December 2011

    CRL checking in IIS 6

    It turns out that it is indeed easy peasy to understand how CRLs work in IIS 6.

    If the certificate contains a CRL Distribution Point (CDP), IIS will try to contact it and if it can’t, 403.13 is your friend.

    Thus CRL checking will always take place in IIS except when:

    • Certificates don’t contain a CDP.
    • CertCheckMode is set to 1 for that particular website.

    Note that if CertCheckMode is not set, IIS takes that to mean enabled and also note that CertCheckMode is set on a website by website basis.

    Simple right?

    I wish I'd found Saurabh Singh's very informative post before I'd spent half the morning messing about with an application server and a CA server trying to work out what was going on. I'd like to believe that I would have reached the same conclusion by myself and I certainly was close, after a myriad of tests revealed that adding a CRL file to the local computer trust store made absolutely no difference, which is what actually prompted me to have another go at googleing for the an answer, but who knows.

    I wonder how IIS 7 deals with CRLs.

    Wednesday, 14 December 2011

    Disable CRL Checking in IIS 6

    It's been a bit of nightmare today, we've had quite a number of issues, ranging from missing CA certs to firewall issues, with routing issues and DNS issues thrown into the mix for good measure.

    One by one we sorted the issues out and we kept getting a 403.13 error. We even got the CRL and followed this, but to now avail.

    Unfortunately, we have no control over the firewall, so we are waiting for this to be sorted out but in the mean time I found how to disable CRL checking in IIS 6. You just need to run the trusted adsutil.vbs script from c:\inetpub\adminscripts like this:
    cscript adsutil.vbs SET w3svc/<websiteid>/CertCheckMode 1
    After setting this, it all started working. To switch CRL checking back on, use this:
    cscript adsutil.vbs SET w3svc/<websiteid>/CertCheckMode 0
    Now I just need to understand how CRL checking works in IIS, easy peasy.

    Sunday, 11 December 2011

    Even More OpenSSL - Client Certificates

    In these posts (1, 2), I discussed using OpenSSL as a simple SSL client to help troubleshoot SSL connections. I did not make any mention of client certificates because, to be honest, we hadn't got that far in our testing, but now that we have and, surprisingly enough, ran into trouble I thought I would discuss using client certificates with OpenSSL. 

    In essence this is the command you need to run:
    openssl s_client -CApath <pathtoCAcerts> -cert <clientcert> -key <clientcertkey> -pass <keypassphrase> -connect <serveripaddress>:443
    where you can substitute CApath for CAfile if you only care about a single CA. The key and pass switches are optional, depending on your client certificate, e.g. if your client certificate has the key in the same file and no pass phrase you can omit them both.
    openssl s_client -CAfile <pathtoCAcert> -cert <clientcert> -connect <serveripaddress>:443
    You'll get something like this, showing only an extract from the response:
    ..
    ..
    ..
    ..
    SSL handshake has read 1548 bytes and written 295 bytes
    ---
    New, TLSv1/SSLv3, Cipher is RC4-MD5
    Server public key is 1024 bit
    Secure Renegotiation IS NOT supported
    Compression: NONE
    Expansion: NONE
    SSL-Session:
        Protocol  : TLSv1
        Cipher    : RC4-MD5
        Session-ID: 92220000BD6498AD833C46B2F3660E6E8131F1233EF25B59A68311394CCBDB8F
        Session-ID-ctx:
        Master-Key: 717135CF0F753CAA1CE67A2713356A05D5C4AB32EE71AAA39F09C1696F865B727D36ACECC9CF8529A0A61C036E1607C7
        Key-Arg   : None
        Krb5 Principal: None
        PSK identity: None
        PSK identity hint: None
        Start Time: 1323622751
        Timeout   : 300 (sec)
        Verify return code: 0 (ok)
    ---
    You now can try to communicate with the server, e.g. try to get a page:
    GET /home.htm
    This should return the contents of home.htm. In actual fact you get the whole server response, not just the page, as is to be expected:
    depth=1 DC = com, DC = dev, CN = TESTAuthority
    verify return:1
    depth=0 C = US, ST = York, L = York, O = York, OU = York, CN = server.dev.com
    verify return:1
    read R BLOCK
    HTTP/1.1 200 OK
    Date: Sun, 11 Dec 2011 17:15:55 GMT
    Server: Microsoft-IIS/6.0
    X-Powered-By: ASP.NET
    X-AspNet-Version: 2.0.50727
    Cache-Control: private, max-age=0
    Content-Type: text/html; charset=utf-8
    Content-Length: 310
    ..
    ..
    ..
    ..
    If you try without the client cert (e.g. openssl s_client -CAfile <pathtoCAcert> -connect <serveripaddress>:443), you will get an error page back (at least from IIS you do), when you try to to communicate with the server (e.g. GET /home.htm). Extract from response:
    <h2>HTTP Error 403.7 - Forbidden: SSL client certificate is required.<br>Internet Information Services (IIS)</h2>

    Thursday, 1 December 2011

    More OpenSSL

    In this post, I stated that the errors, see below in red, were due to the linux server not trusting the TESTAuthority CA, which is true and false. It's true in the strictest sense of the word, it's false in the sense that unlike Windows, Linux does not have a central repository for certificates and thus the concept of a Linux server trusting a CA is not quite correct.
    CONNECTED(00000003)
    depth=0 C = US, ST = York, L = York, O = York, OU = York, CN = crmdevbox.dev.com
    verify error:num=20:unable to get local issuer certificate
    verify return:1
    depth=0 C = US, ST = York, L = York, O = York, OU = York, CN = crmdevbox.dev.com
    verify error:num=27:certificate not trusted
    verify return:1
    depth=0 C = US, ST = York, L = York, O = York, OU = York, CN = crmdevbox.dev.com
    verify error:num=21:unable to verify the first certificate
    verify return:1
    Since Linux does not have a central certificate repository we need to pass the CA certificate file to openssl, which we can do with the following command (Note that there is a -CApath switch to pass a directory rather than a single file, in case you want to store multiple CAs in the same place.):

    openssl s_client -CAfile testauth.cer -connect server.dev.com:443

    CONNECTED(00000003)
    ---
    Certificate chain
     0 s:/C=US/ST=Yorkshire/L=Yorkshire/O=PHP/OU=PHP/CN=server.dev.com
       i:/DC=com/DC=dev/CN=TESTAuthority
    ---
    Server certificate
    -----BEGIN CERTIFICATE-----
    MIIFgDCCBGigAwIBAgIKIkXHKgAAAAAAJzANBgkqhkiG9w0BAQUFADBCMRMwEQYK
    CZImiZPyLGQBGRYDY29tMRMwEQYKCZImiZPyLGQBGRYDZGV2MRYwFAYDVQQDEw1U
    RVNUQXV0aG9yaXR5MB4XDTExMTAyNTA4NTUwOFoXDTEzMTAyNDA4NTUwOFowajEL
    MAkGA1UEBhMCVVMxEjAQBgNVBAgTCVlvcmtzaGlyZTESMBAGA1UEBxMJU2hlZmZp
    ZWxkMQswCQYDVQQKEwGIUDELMArGA1UECxMCSFAxGTAXBgNVBAMTEGRoejMwNzAx
    LmRldi5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANNYoEklD7Rgnoq0
    Ld1+YkKNVcMy9CLb40kmQ0E5f+7SXPDMqNS12yk81k21PQoioOVPSKG2+pAls/vw
    QhbjMBeRXeYkrH6V5+nuBYogRVZil0xMeK5+lOJYwig+rHkd5bo8OU/ep+m0VaPj
    k2k9+Ns3ZZ1FwlRf+s0KiT1iKVY1AgMBAAGjggLSMIICzjALBgNVHQ8EBAMCBaAw
    RAYJKoZIhvcNAQkPBDcwNTAOBggqhkiG9w0DAgICAIAwDgYIKoZIhvcNAwQCAgCA
    MAcGBSsOAwIHMAoGCCqGSIb3DQMHMBMGA1UdJQQMMAoGCCsGAQUFBwMBMB0GA1Ud
    DgQWBBS6N5Bqj8MOTu9CmsXJXcE+sWRDlDAfBgNVHSMEGDAWgBQiuWOMgDSyXO0d
    pdlFswWLTcSM+TCB9gYDVR0fBIHuMIHrMIHooIHloIHihoGtbGRhcDovLy9DTj1U
    RVNUQXV0aG9yaXR5LENOPW1hcnMsQ049Q0RQLENOPVB1YmxpYyUyMEtleSUyMFNl
    cnZpY2VzLENOPVNlcnZpY2VzLENOPUNvbmZpZ3VyYXRpb24sREM9ZGV2LERDPWNv
    bT9jZXJ0aWZpY2F0ZVJldm9jYXRpb25MaXN0P2Jhc2U/b2JqZWN0Q2xhc3M9Y1JM
    RGlzdHJpYnV0aW9uUG9pbnSGMGh0dHA6Ly9tYXJzLmRldi5jb20vQ2VydEVucm9s
    bC9URVNUQXV0aG9yaXR5LmNybDCCAQYGCCsGAQUFBwEBBIH5MIH2MIGoBggrBgEF
    BQcwAoaBm2xkYXA6Ly8vQ049VEVTVEF1dGhvcml0eSxDTj1BSUEsQ049UHVibGlj
    JTIwS2V5JTIwU2VydmljZXMsQ049U2VydmljZXMsQ049Q29uZmlndXJhdGlvbixE
    Qz1kZXYsREM9Y29tP2NBQ2VydGlmaWNhdGU/YmFzZT9vYmplY3RDbGFzcz1jZXJ0
    aWZpY2F0aW9uQXV0aG9yaXR5MEkGCCsGAQUFBzAChj1odHRwOi8vbWFycy5kZXYu
    Y29tL0NlcnRFbnJvbGwvbWFycy5kZXYuY29tX1RFU1RBdXRob3JpdHkuY3J0MCEG
    CSsGAQQBgjcUAgQUHhIAVwBlAGIAUwBlAHIAdgBlAHIwDQYJKoZIhvcNAQEFBQAD
    ggEBAKPrAW4nxI8AaNWpWHGnEHsUBy9C9jFEVLLXxP7jyawmfEgcBBpl+osxH1hG
    FSFxYRa5ZVMhj6wMBMHlleftDZ7y5TunKFkOMqHhB027/SmYoqWw/XyWJxW8/EUq
    9i3L5Aw1PV+/oF6Nm05VehXRlXF0ngHcwC4EYFCjt4R+/f7prMZHdvIZUq9VhtcV
    VHdOl2NE7QizXdebrlyU5cIoS98XySgDuSjGeIOYY/z03jFghKv62qK5ituqQWYY
    S17m516w5fSebBYhVfL5YZoCg5OXo346iZU320a6i5dZWHDDq89GkNp3i8aPxSZL
    GyHRoPJzDBzo6WR+212a4j3zTEE=
    -----END CERTIFICATE-----
    subject=/C=US/ST=Yorkshire/L=Yorkshire/O=PHP/OU=PHP/CN=server.dev.com
    issuer=/DC=com/DC=dev/CN=TESTAuthority
    ---
    No client certificate CA names sent
    ---
    SSL handshake has read 1548 bytes and written 295 bytes
    ---
    New, TLSv1/SSLv3, Cipher is RC4-MD5
    Server public key is 1024 bit
    Secure Renegotiation IS NOT supported
    Compression: NONE
    Expansion: NONE
    SSL-Session:
        Protocol  : TLSv1
        Cipher    : RC4-MD5
        Session-ID: D0210000497E9440E880E5360922751D08D60E7A480423FED6A6DCD78F88F9CF
        Session-ID-ctx:
        Master-Key: 350CEA4DCCC35DE78660106649A61B31EE78716BDDBDC7AF3EC1FF53C0C9885DB7529CC3854EA88881C73C596672570B
        Key-Arg   : None
        Krb5 Principal: None
        PSK identity: None
        PSK identity hint: None
        Start Time: 1322744645
        Timeout   : 300 (sec)
        Verify return code: 0 (ok)
    ---
    No complaints about certificates now.:)

    Saturday, 26 November 2011

    Disabling Low ciphers in IIS 6.0

    I discussed yesterday that we had done some security hardening for our IIS 6.0 servers. In essence, we have disabled Low ciphers, i.e. those with a key length shorter than 128 bits as well as SSL 2.0. 
    For some annoying reason you have to actually disable the ciphers by creating the Enabled Dword key and setting it to 0. If it's not there, the system will assume that it's ok to use it the cipher.

    You can copy and paste the text in italics to a file, save it with .reg extension and then simply double click on it to apply to your server.
    Windows Registry Editor Version 5.00 
    [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Ciphers\DES 56/56]
    "Enabled"=dword:00000000

    [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Ciphers\RC2 40/128]
    "Enabled"=dword:00000000

    [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Ciphers\RC4 40/128]
    "Enabled"=dword:00000000

    [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Ciphers\RC4 56/128]
    "Enabled"=dword:00000000

    [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 2.0\Server]
    "Enabled"=dword:00000000

    Friday, 25 November 2011

    The joys of SSL - Cipher Levels

    A few weeks ago we were tasked with ensuring that our IIS 6.0 server only allowed Medium and High ciphers, so in order to test what ciphers IIS accepted I used openssl from a linux box in our dev environment, like this.
    openssl s_client -connect 10.168.20.109:443 -cipher NULL
    CONNECTED(00000003)

    140587511035720:error:140790E5:SSL routines:SSL23_WRITE:ssl handshake failure:s23_lib.c:184:

    ---

    no peer certificate available

    ---

    No client certificate CA names sent

    ---

    SSL handshake has read 0 bytes and written 61 bytes

    ---

    New, (NONE), Cipher is (NONE)

    Secure Renegotiation IS NOT supported

    Compression: NONE

    Expansion: NONE

    ---

    Cool, we don't accept Null ciphers

    Let's try now with low ciphers


    openssl s_client -connect 10.168.20.109:443 -cipher LOW
    CONNECTED(00000003)
    depth=0 C = US, ST = York, L = York, O = York, OU = York, CN = crmdevbox.dev.com
    verify error:num=20:unable to get local issuer certificate
    verify return:1
    depth=0 C = US, ST = York, L = York, O = York, OU = York, CN = crmdevbox.dev.com
    verify error:num=27:certificate not trusted
    verify return:1
    depth=0 C = US, ST = York, L = York, O = York, OU = York, CN = crmdevbox.dev.com
    verify error:num=21:unable to verify the first certificate
    verify return:1
    ---
    Certificate chain
     0 s:/C=US/ST=York/L=York/O=York/OU=York/CN=crmdevbox.dev.com
       i:/DC=com/DC=dev/CN=TESTAuthority
    ---
    Server certificate
    -----BEGIN CERTIFICATE-----
    MIIFgDCCBGigAwIBAgIKIkXHKgAAAAAAJzANBgkqhkiG9w0BAQUFADBCMRMwEQYK
    CZImiZPyLGQBGRYDY29tMRMwEQYKCZImiZPyLGQBGRYDZGV2MRYwFAYDVQQDEw1U
    RVNUQXV0aG9yaXR5MB4XDTExMTAyNTA4NTUwOFoXDTEzMTAyNDA4NTUwOFowajEL
    MAkGA1UEBhMCVVMxEjAQBgNVBAgTCVlvcmtzaGlyZTESMBAGA1UEBxMJU2hlZmZp
    ZWxkMQswCQYDVQQKEwJIUDELMAkGA1UECxMCSFAxGTAXBgNVBAMTEGRoejMwNzAx
    LmRldi5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANNYoEklD7Rgnoq0
    Ld1+YkKNVcMy9CLb40kmQ0E5f+7SXPDMqNS12yk81k21PQoioOVPSKG2+pAls/vw
    QhbjMBeRXeYkrH6V5+nuBYogRVZil0xMeK5+lOJYwig+rHkd5bo8OU/ep+m0VaPj
    k2k9+Ns3ZZ1FwlRf+s0KiT1iKVY1AgMBAAGjggLSMIICzjALBgNVHQ8EBAMCBaAw
    RAYJKoZIhvcNAQkPBDcwNTAOBggqhkiG9w0DAgICAIAwDgYIKoZIhvcNAwQCAgCA
    MAcGBSsOAwIHMAoGCCqGSIb3DQMHMBMGA1UdJQQMMAoGCCsGAQUFBwMBMB0GA1Ud
    DgQWBBS6N5Bqj8MOTu9CmsXJXcE+sWRDlDAfBgNVHSMEGDAWgBQiuWOMgDSyXO0d
    pdlFswWLTcSM+TCB9gYDVR0fBIHuMIHrMIHooIHloIHihoGtbGRhcDovLy9DTj1U
    RVNUQXV0aG9yaXR5LENOPW1hcnMsQ049Q0RQLENOPVB1YmxpYyUyMEtleSUyMFNl
    cnZpY2VzLENOPVNlcnZpY2VzLENOPUNvbmZpZ3VyYXRpb24sREM9ZGV2LERDPWNv
    bT9jZXJ0aWZpY2F0ZVJldm9jYXRpb25MaXN0P2Jhc2U/b2JqZWN0Q2xhc3M9Y1JM
    RGlzdHJpYnV0aW9uUG9pbnSGMGh0dHA6Ly9tYXJzLmRldi5jb20vQ2VydEVucm9s
    bC9URVNUQXV0aG9yaXR5LmNybDCCAQYGCCsGAQUFBwEBBIH5MIH2MIGoBggrBgEF
    BQcwAoaBm2xkYXA6Ly8vQ049VEVTVEF1dGhvcml0eSxDTj1BSUEsQ049UHVibGlj
    JTIwS2V5JTIwU2VydmljZXMsQ049U2VydmljZXMsQ049Q29uZmlndXJhdGlvbixE
    Qz1kZXYsREM9Y29tP2NBQ2VydGlmaWNhdGU/YmFzZT9vYmplY3RDbGFzcz1jZXJ0
    aWZpY2F0aW9uQXV0aG9yaXR5MEkGCCsGAQUFBzAChj1odHRwOi8vbWFycy5kZXYu
    Y29tL0NlcnRFbnJvbGwvbWFycy5kZXYuY29tX1RFU1RBdXRob3JpdHkuY3J0MCEG
    CSsGAQQBgjcUAgQUHhIAVwBlAGIAUwBlAHIAdgBlAHIwDQYJKoZIhvcNAQEFBQAD
    ggEBAKPrAW4nxI8AaNWpWHGnEHsUBy9C9jFEVLLXxP7jyawmfEgcBBpl+osxH1hG
    FSFxYRa5ZVMhj6wMBMHlleftDZ7y5TunKFkOMqHhB027/SmYoqWw/XyWJxW8/EUq
    9i3L5Aw1PV+/oF6Nm05VehXRlXF0ngHcwC4EYFCjt4R+/f7prMZHdvIZUq9VhtcV
    VHdOl2NE7QizXdebrlyU5cIoS98XySgDuSjGeIOYY/z03jFghKv62qK5ituqQWYY
    S17m516w5fSebBYhVfL5YZoCg5OXo346iZU320a6i5dZWHDDq89GkNp3i8aPxSZL
    GyHRoPJzDBzo6WR+212a4j3zTEE=
    -----END CERTIFICATE-----
    subject=/C=US/ST=York/L=York/O=York/OU=York/CN=crmdevbox.dev.com
    issuer=/DC=com/DC=dev/CN=TESTAuthority
    ---
    No client certificate CA names sent
    ---
    SSL handshake has read 1556 bytes and written 251 bytes
    ---
    New, TLSv1/SSLv3, Cipher is DES-CBC-SHA
    Server public key is 1024 bit
    Secure Renegotiation IS NOT supported
    Compression: NONE
    Expansion: NONE
    SSL-Session:
        Protocol  : TLSv1
        Cipher    : DES-CBC-SHA
        Session-ID: B51700000B4CA5D162B9D228487DCCC53694945999BBE6F50BF1332ED8DA3D28
        Session-ID-ctx:
        Master-Key: E477BEE6E2A4D51D5FCAFB9AC385F89ED3FFDE06F4EEC5860A5080D655D18EDA3E483D7FA0CCE0EEDD454E9C3A847367
        Key-Arg   : None
        Krb5 Principal: None
        PSK identity: None
        PSK identity hint: None
        Start Time: 1322229571
        Timeout   : 300 (sec)
        Verify return code: 21 (unable to verify the first certificate)
    oops, we do. Incidentally, I think the error (unable to verify the first certificate) is due to the linux box not trusting TESTAuthority.

    So we did a little bit of hardening, which I'll post about separately, and now when we try again:
    openssl s_client -connect 10.168.20.109:443 -cipher LOW
    CONNECTED(00000003)

    140587511035720:error:140790E5:SSL routines:SSL23_WRITE:ssl handshake failure:s23_lib.c:184:

    ---

    no peer certificate available

    ---

    No client certificate CA names sent

    ---

    SSL handshake has read 0 bytes and written 61 bytes

    ---

    New, (NONE), Cipher is (NONE)

    Secure Renegotiation IS NOT supported

    Compression: NONE

    Expansion: NONE

    ---

    Result.

    You can try with Medium or High ciphers too.

    Sunday, 6 November 2011

    Null Ciphers in .NET Framework.

    We get some strange requests at work form time to time, the last one? Can you use null ciphers for SSL traffic in IIS?

    If you are wondering why you might want to do this, I don't have a ready answer to be honest. In *nix land, this isn't a major problem, but IIS does not support it at all (at least for versions 5-7.5).
    To be able to handle a Null cipher, Schannel needs to have certain values

    dwMinimumCipherStrength
    Minimum bulk encryption cipher strength, in bits, allowed for connections. If this member is zero, SCHANNEL uses the system default.
    If this member is -1, only the SSL3/TLS MAC-only cipher suites (also known as NULL cipher) are enabled.

    dwMaximumCipherStrength
    Maximum bulk encryption cipher strength, in bits, allowed for connections. If this member is zero, SCHANNEL uses the system default.
    If this member is -1, only the SSL3/TLS MAC-only cipher suites (also known as NULL cipher) are enabled. In this case, dwMinimumCipherStrength must be set to -1.

    However - it is not these properties alone. You cannot enable NULL ciphers through the registry only. The SCHANNEL caller has to OPT IN by passing -1 to the appropriate fields in the SCHANNEL cred. IIS does not allow NULL ciphers as they do not pass in -1 to the SCHANNEL cred.
    This leaves you needing some sort of proxy server that accepts Null Ciphers for the SSL handshake so that the proxy completes the handshake and then forwards the request to IIS.

    If you wanted to create your own proxy, this is probably a very bad idea by the way, the .NET framework can help you. From version 4.0, it is possible to allow null ciphers on the SSLStream constructor by simply setting Encryption policy to AllowNoEncryption, like this:

       1 SslStream sslStream = new SslStream(myclient.GetStream(), false, null, null, EncryptionPolicy.AllowNoEncryption);
    

    where myclient is a TcpClient object.

    I still have to ask why, though, why?