Archive for the 'security' Category

Jul 24 2008

WCF, certificates, event logs and silly security exceptions

Published by Raja Nadar under security, wcf

my friend was working on certificate based WCF transport messages. she prototyped a demo, and was testing it out. she kept on hitting the following exception:

Found multiple X.509 certificates using the following search criteria: StoreName ‘My’, StoreLocation ‘LocalMachine’, FindType ‘FindBySubjectName’, FindValue ”. Provide a more specific find value.

the error message could not have been more concise.. I had a look at the code, and there was nothing programmatic to verify. it was all WCF configuration driven [that I like so much J].

the configuration for binding was as follows:

<bindings>

  <wsHttpBinding>

    <binding name=wsHttpEndpointBinding>

      <security mode=Message>

        <message clientCredentialType=Certificate />

      </security>

    </binding>

  </wsHttpBinding>

</bindings>

the configuration for service credentials was as follows:

<serviceCredentials>

  <clientCertificate>

    <certificate storeLocation=LocalMachine storeName=My

                 x509FindType=FindBySubjectName />

    <authentication revocationMode=Online trustedStoreLocation=CurrentUser />

  </clientCertificate>

  <serviceCertificate findValue=rajanadar.com storeName=My

                      storeLocation=LocalMachine

    x509FindType=FindBySubjectName />

</serviceCredentials>

I thought, the search ‘rajanadar.com’ may be returning more than one certificate from the store. (may be due to root certificates etc.., I don’t know)

I checked my certificate store, and gave a specific (unique) Subject Name and tried different things.

no luck, still the same issue.

after a little observation, I read the error message a little more carefully.. (why didn’t I do this the first time?)

Found multiple X.509 certificates using the following search criteria: StoreName ‘My’, StoreLocation ‘LocalMachine’, FindType ‘FindBySubjectName’, FindValue ”. Provide a more specific find value.

it complained of a blank ‘FindValue’

then it struck me that we missed the FindValue for the client certificate, not the service certificate.

The corrected configuration was:

<serviceCredentials>

  <clientCertificate>

    <certificate storeLocation=LocalMachine storeName=My

        x509FindType=FindBySubjectName findValue=uniqueclient.rajanadar.com />

    <authentication revocationMode=Online trustedStoreLocation=CurrentUser />

  </clientCertificate>

  <serviceCertificate findValue=server.rajanadar.com storeName=My

             storeLocation=LocalMachine x509FindType=FindBySubjectName />

</serviceCredentials>

that solved the issue. it was a simple silly mistake. (obviously only after it was caught)

 

the next error I encountered, sounded something like:

Unhandled Exception: System.Net.WebException: The underlying connection was closed: Could not establish secure channel for SSL/TLS.

 

Fortunately, my past sleight of hand on WSE and SSL certificates, quickly reminded me that, when dealing with Web Applications, I need to give sufficient access permissions to the aspnet user account, to the PFX files of the certificates.

I modified the access permissions of the PFX file in question, (yeah the \AppData\Microsoft\Crypto\RSA\MachineKeys path) and the application seemed to work without any more issues. silly things, nonetheless there’s a first time..

 

p.s. the aspnet user account permission issue reminds me of one more classic issue that I encountered most of the times..

[SecurityException: Requested registry access is not allowed.] 

Microsoft.Win32.RegistryKey.OpenSubKey(String name, Boolean writable)

System.Diagnostics.EventLog.FindSourceRegistration(String source, String machineName, Boolean readOnly)

System.Diagnostics.EventLog.SourceExists(String source, String machineName) +79

System.Diagnostics.EventLog.SourceExists(String source)

 

this is again because, creating a new event log or event source, needs registry write permissions, typically not possessed by the aspnet account.

 

Solution: initially, I used to grant write permissions to the registry keys

(HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\NewLog or HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\Application\Source)
 

But then, this is not a good security approach. during the lifetime of the application, it just needs to write to the event logs and never create new ones. Hence I created the new registry keys (effectively new event logs/sources) using my Installers, and granted read permissions to the web application accounts. this sounded good.

 

there’s a solution to every problem; given enough time and sometimes, well, just time…

3 responses so far

May 20 2008

X509Certificate properties

Published by Raja Nadar under WSE, c#, security

as part of some WSE implementation, I had a small utility to read the details of a X509 Certificate. especially the SKID (Subject Key Identifier), of the certificate. actually, WSE comes with a certificate reader tool, which reads the SKID of the certificate.

however, i had 2 issues, using this tool:

  • i needed to read the properties from a file, which was the  X509 certificate, instead of reading it from the certificate stores.
  • i also needed a string representation of the certificate to be stored in the database. (i like the idea of a database oriented certificate management)

In order to read the X509Certificate properties, there are 2 namespaces available.

 

using Microsoft.Web.Services2.Security.X509;
using System.Security.Cryptography.X509Certificates;

 however, of the 2 namespaces,  the Microsoft.Web.Services2.Security.X509 seems to give the Subject Key Identifier of the certificate. it makes all the more sense to use this namespace, when you are working with WSE enabled web services.

the code snippet to read the certificate properties: (certificate is assumed to be in a file location)

 

using (FileStream stream = new FileStream(certificateFilePath, FileMode.Open))
{
    byte[] blob = new byte[(int)stream.Length];
    stream.Read(blob, 0, (int)stream.Length);
 
    using (X509Certificate cert = new X509Certificate(blob))
    {
        this.textBoxBlob.Text = Convert.ToBase64String(blob);
        this.textBoxSubject.Text = cert.Subject;
        this.textBoxTokenIssuer.Text = cert.Issuer;
        this.textBoxSKID.Text = Convert.ToBase64String(cert.GetKeyIdentifier());
        this.textBoxExpiry.Text = cert.GetExpirationDateString();
    }
}

Notes:

  • You can get the WSE DLL from here.
  • the X509Certificate belongs to the Microsoft.Web.Services2.Security.X509 namespace.
  • Convert.ToBase64String(blob) is very useful if you want to store the certificate in a database field. it is one of the ways to eliminate certificate management, for your application.
  • The Subject Key Identifier is what uniquely identifies your certificate. when WSE is used in a declarative manner, typically the SKID, Subject and Token Issuer are used in the configuration files.

 there’s a solution to every problem; given enough time and money..

No responses yet