A Dutch software developer living in Chile

Monday, June 08, 2009
Remoting or WCF?
.Net Remoting sounds old, and it is essentially old. Though this is a technique not commonly used and not so popular, it is still valid and it still works today. (Even in .Net 4.0) WCF has gained more popularity since .Net 3.0. Now WCF is popular and .Net Remoting is nearly forgotten. Still, I have to use .Net Remoting because some of my customers are still using – glump – Windows 2000. Guess what Windows 2000 supports? Only .Net 2.0.
.Net Remoting supports almost any host, including IIS. Just like WCF, you can create your own Windows Service to host your Remoting objects or host them in IIS. There are some considerations that you should take when using .Net Remoting, but once you’ve gotten used to it, you’ll see that it’s quite a easy way to establish inter-process communication.
So time for some examples… For this example we’ll use 3 assemblies. One class library and 2 console applications.
First, let’s create a remotable object in a class library:
using System;
using System.Collections.Generic;
using System.Text;
namespace MyRemoteObjects
{
public class RemotableObject : MarshalByRefObject
{
public RemotableObject()
{
startTime = DateTime.Now;
}
private DateTime startTime;
public DateTime GetDateTime()
{
Console.WriteLine("Someone wants to know the time");
return DateTime.Now;
}
~RemotableObject()
{
Console.WriteLine("I'm shut down after {0}", DateTime.Now - startTime);
}
}
}
Next, here’s the source code for the server application:
using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;
using System.Collections.Generic;
using System.Text;
using MyRemoteObjects;
namespace MyRemoteService
{
class Program
{
static void Main(string[] args)
{
HttpChannel channel = new HttpChannel(8080);
ChannelServices.RegisterChannel(channel, false);
RemotableObject object1 = new RemotableObject();
Console.WriteLine("I'm the server");
ObjRef ref1 = RemotingServices.Marshal(object1, "object1uri");
Console.WriteLine("ObjRef.URI: {0}", ref1.URI);
Console.WriteLine("Press enter to quit the app");
Console.ReadLine();
// tear down
RemotingServices.Disconnect(object1);
ChannelServices.UnregisterChannel(channel);
// The ServiceClass object's Finalize method writes a message to
// the console. A single object will almost always succeed in
// running its Finalize method before the Console is finalized;
// in a larger application, you could ensure that all objects
// finalize before the application ends by calling the garbage
// collector and waiting.
GC.Collect();
GC.WaitForPendingFinalizers();
}
}
}
Last, here’s the source for the client application:
using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;
using System.Collections.Generic;
using System.Text;
using MyRemoteObjects;
namespace RemotingExample
{
class Program
{
static void Main(string[] args)
{
HttpChannel channel = new HttpChannel(0);
ChannelServices.RegisterChannel(channel, false);
RemotingConfiguration.RegisterWellKnownClientType(typeof(RemotableObject), "http://localhost:8080/object1uri");
RemotableObject remObject = new RemotableObject();
Console.WriteLine("I'm the client");
try
{
Console.WriteLine("The time on the server is: {0}", remObject.GetDateTime());
}
catch (Exception ex)
{
Console.WriteLine("Oops: {0}", ex);
}
Console.ReadLine();
}
}
}
After building and running this, you’ll get something like this:
If you would put this into a service, you can actually talk with your Windows service without much of a hassle. Hope this helps! Objects that are passed from the server to the client need to be either serializable or inherited from MarshalByRefObject.
Monday, June 08, 2009 1:16:06 PM (Pacific SA Standard Time, UTC-04:00)
Working on a new theme for this blog
I’m not happy with the current blue theme… The navigation is overlapped by code segments,
the text gets too wide on big wide-screen monitors
and last but not least, the text is simply too tiny. (Even on a 87 DPI screen it’s hard to read.) So I’ll be changing the theme any day now, to something somewhat more appealing and more usable. If you’ve got some suggestions, feel free to share them! You can comment on this post, or mail me.
Monday, June 08, 2009 11:48:03 AM (Pacific SA Standard Time, UTC-04:00)
Which search engine is best for you?
Take a look at http://blindsearch.fejus.com/. Here you can test your favorite searches and see which engine is best for you. Just search about 10 times and see which engine had the best results 
Monday, June 08, 2009 11:42:14 AM (Pacific SA Standard Time, UTC-04:00)

Sunday, June 07, 2009
Scripting in .Net
So you want to script C#? It’s very easy! For these examples in this article, we’ll use a script file called: “MyScript.cs” which is not compiled in the solution but simple marked as a content file. The contents of that file should look like this:
using System;
static class Program
{
[STAThread]
public static void Main()
{
System.Console.WriteLine("Hello world");
}
}
Next, let’s create a simple compiler to compile this script:
using System;
using System.Collections.Generic;
using System.Text;
using System.CodeDom.Compiler;
using Microsoft.CSharp;
using System.IO;
using System.Reflection;
namespace ScriptRunner
{
class Program
{
static void Main(string[] args)
{
CSharpCodeProvider provider = new CSharpCodeProvider();
CompilerParameters compilerParameters = new CompilerParameters();
compilerParameters.IncludeDebugInformation = true;
compilerParameters.GenerateExecutable = false;
compilerParameters.GenerateInMemory = true;
string source = File.ReadAllText("MyScript.cs");
CompilerResults results = provider.CompileAssemblyFromSource(compilerParameters, new string[] { source });
if (results.Errors.Count > 0)
{
foreach (var item in results.Errors)
{
Console.WriteLine(item);
}
}
else
{
if (results.CompiledAssembly != null)
{
BindingFlags flags = BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public;
Assembly asm = results.CompiledAssembly;
Type progType = asm.GetType("Program");
MethodInfo info = progType.GetMethod("Main", flags);
if (info != null)
{
info.Invoke(null, BindingFlags.NonPublic, null, null, null);
//asm.EntryPoint.Invoke(null, new object[0]);
}
else
{
Console.WriteLine("Entrypoint not found!");
foreach (var item in asm.GetTypes())
{
Console.WriteLine(item.FullName);
foreach (var method in item.GetMethods(flags))
{
Console.WriteLine(item.FullName + "." + method.Name);
}
}
}
}
}
Console.ReadLine();
}
}
}
No magic here, the result will be as expected:
Now what can we do with this? We can add scripting to our app… but wait, couldn’t that break my app? Yup, if someone decides to create a piece of script that generates an exception, loads huge files, etc, it will sooner or later break your app right with it… These are the kind of things you want to put inside an AppDomain, maybe even sandboxed with partial trust…
The idea is that a piece of code should be able to access certain items from your app. Interfaces and attributes are the preferred approach for these situations. Let’s create a plugin interface, and a marker attribute so we’ll be able to find it once the plugin gets compiled. For this, we’ll create a separate assembly which is called “PluginSDK” and this will contain a few interfaces.
The host interface:
namespace ScriptRunnerSDK
{
public interface IHost
{
string Name { get; }
}
}
The plugin interface:
namespace ScriptRunnerSDK
{
public interface IPlugin
{
string Execute();
IHost Host { get; set; }
}
}
And finally, the plugin attribute:
using System;
namespace ScriptRunnerSDK
{
[global::System.AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
public sealed class PluginAttribute : Attribute
{
readonly string name;
// This is a positional argument
public PluginAttribute(string name)
{
this.name = name;
}
public string Name
{
get { return name; }
}
}
}
Now it’s time to change our sample script to something that actually uses this info.
using System;
using ScriptRunnerSDK;
[Plugin("MyPlugin")]
class Program : IPlugin
{
public Program()
{
}
public string Execute()
{
Console.WriteLine("I am running in domain: {0}", AppDomain.CurrentDomain.FriendlyName);
return String.Format("Hello {0}", Host.Name);
}
private IHost _host;
public IHost Host
{
get
{
return _host;
}
set
{
_host = value;
}
}
}
And finally, let’s create our compiler that loads the script, compiles it, runs it in a separate AppDomain providing a host and will terminate the script once it is done.
using System;
using System.CodeDom.Compiler;
using System.IO;
using System.Reflection;
using Microsoft.CSharp;
using ScriptRunnerSDK;
namespace ScriptRunner
{
class Program
{
static void Main(string[] args)
{
string source = File.ReadAllText("MyScript.cs");
DummyHost host = new DummyHost();
AppDomain scriptDomain = null;
try
{
scriptDomain = AppDomain.CreateDomain("Script domain");
Type workerType = typeof(ScriptWorker);
ScriptWorker worker = (ScriptWorker)scriptDomain.CreateInstanceAndUnwrap(workerType.Assembly.FullName, workerType.FullName);
string result = worker.RunScript("MyPlugin", source, host);
Console.WriteLine(result);
}
finally
{
if (scriptDomain != null)
AppDomain.Unload(scriptDomain);
}
Console.ReadLine();
}
}
public class DummyHost : MarshalByRefObject, IHost
{
public DummyHost()
{
}
#region IHost Members
public string Name
{
get { return "DummyHost"; }
}
#endregion
}
public class ScriptWorker : MarshalByRefObject
{
public string RunScript(string pluginName, string script, IHost host)
{
string result = String.Empty;
CompilerResults results = Compile(script);
if (results.Errors.Count > 0)
{
foreach (var item in results.Errors)
{
Console.WriteLine(item);
}
}
else
{
result = RunCompiledScript(results.CompiledAssembly, pluginName, host);
}
return result;
}
private string RunCompiledScript(Assembly assembly, string pluginName, IHost host)
{
Type pluginType = null;
// Find the plugin attribute in the assembly's types, see if it matches the plugin name and if so, construct the type, pass the host and execute the plugin.
foreach (var type in assembly.GetTypes())
{
PluginAttribute[] attr = type.GetCustomAttributes(typeof(PluginAttribute), false) as PluginAttribute[];
if (attr != null && attr.Length > 0 && String.Equals(attr[0].Name, pluginName, StringComparison.OrdinalIgnoreCase))
{
pluginType = type;
break;
}
}
// Did we find the type?
if (pluginType != null)
{
IPlugin plugin = pluginType.GetConstructor(new Type[0]).Invoke(new object[0]) as IPlugin;
plugin.Host = host;
return plugin.Execute();
}
// No, we didn't...
throw new InvalidOperationException("The plugin specified could not be found");
}
CompilerResults Compile(string source)
{
CSharpCodeProvider provider = new CSharpCodeProvider();
CompilerParameters compilerParameters = new CompilerParameters();
compilerParameters.IncludeDebugInformation = true;
compilerParameters.GenerateExecutable = false;
compilerParameters.GenerateInMemory = true;
// Add a reference assembly
compilerParameters.ReferencedAssemblies.Add("ScriptRunnerSDK.dll");
CompilerResults results = provider.CompileAssemblyFromSource(compilerParameters, new string[] { source });
return results;
}
}
}
This is all there’s to it
The result looks like this:
You can read in my previous post how to do error handling on remote AppDomains to provide additional stability to your application.
Sunday, June 07, 2009 3:03:50 PM (Pacific SA Standard Time, UTC-04:00)
Running code in a different AppDomain
Let’s say you would like to be able to extend your application with C# scripting abilities. You can do this by simply compiling the script and running it. The problem is that these kind of scripts take up memory that isn’t going to be released any time soon. Another problem is that the script can do anything your program can… or when an exception is thrown, your program crashes… is that really the idea?
Enter the use of application domains. Application domains are just for doing these kind of things. Loading temporary assemblies, executing partially trusted code and do memory-intensive work so you don’t need to GC.Collect at the end of the day. (Normally we wouldn’t want to interfere with .Net memory management, because there wouldn’t be much reason to. .Net does a very good job all by itself!)
Let’s start with a very simple example:
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
namespace MyAppDomain
{
class Program
{
static void Main(string[] args)
{
Worker localWorker = new Worker();
Console.WriteLine("localWorker is running in: {0}", localWorker.DomainName);
AppDomain myDomain = null;
try
{
myDomain = AppDomain.CreateDomain("Remote Domain");
Worker remoteWorker = (Worker)myDomain.CreateInstanceAndUnwrap(Assembly.GetExecutingAssembly().FullName, "MyAppDomain.Worker");
Console.WriteLine("remoteWorker is running in: {0}", remoteWorker.DomainName);
}
finally
{
if (myDomain != null)
AppDomain.Unload(myDomain);
}
}
}
public class Worker : MarshalByRefObject
{
public Worker()
{
}
public string DomainName
{
get
{
return AppDomain.CurrentDomain.FriendlyName;
}
}
}
}
What you see here is:
- An application domain is created
- A value is sent from the new application domain back to the local domain.
- We have a strongly-typed reference to the remote object
In this example, the remote domain is running with the same privileges as the local domain.
Let’s crash…
Unhandled exceptions can cause code to crash or leave your application in an unstable state. AppDomains are isolated and can help you to catch unhandled exceptions and unload the application domain when needed. So when we expand our example to include this, we get something like this:
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
namespace MyAppDomain
{
class Program
{
static void Main(string[] args)
{
AppDomain myDomain = null;
try
{
myDomain = AppDomain.CreateDomain("Remote Domain");
myDomain.UnhandledException += new UnhandledExceptionEventHandler(myDomain_UnhandledException);
Worker remoteWorker = (Worker)myDomain.CreateInstanceAndUnwrap(Assembly.GetExecutingAssembly().FullName, typeof(Worker).FullName);
remoteWorker.VeryBadMethod();
}
catch(Exception ex)
{
myDomain_UnhandledException(myDomain, new UnhandledExceptionEventArgs(ex, false));
}
finally
{
if (myDomain != null)
AppDomain.Unload(myDomain);
}
Console.ReadLine();
}
static void myDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Exception ex = e.ExceptionObject as Exception;
if (ex != null)
Console.WriteLine(ex.Message);
else
Console.WriteLine("A unknown exception was thrown");
}
}
public class Worker : MarshalByRefObject
{
public Worker()
{
}
public string DomainName
{
get
{
return AppDomain.CurrentDomain.FriendlyName;
}
}
public void VeryBadMethod()
{
// Autch!
throw new InvalidOperationException();
}
}
}
Loading assemblies in the remote application domain
When loading an assembly in the remote domain, the assembly gets unloaded once the application domain gets unloaded. So if Worker would load an assembly, this would not be a problem as long as worker is in a separate domain. Here’s another example.
First, we create a simply plugin assembly:
using System;
using System.Collections.Generic;
using System.Text;
namespace MyPluginAssembly
{
public class MyPlugin
{
public MyPlugin()
{
}
public string Hello()
{
return "Hello";
}
}
}
This assembly needs to be compiled and for the sake of simplicity we’ll call it “MyPluginAssembly.dll”. Copy this dll to the same directory as the MyAppDomain output folder. Next, we’ll change the example a bit and load the assembly, do some reflection, run the Hello method and print the result.
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
namespace MyAppDomain
{
class Program
{
static void Main(string[] args)
{
AppDomain myDomain = null;
try
{
myDomain = AppDomain.CreateDomain("Remote Domain");
myDomain.UnhandledException += new UnhandledExceptionEventHandler(myDomain_UnhandledException);
Worker remoteWorker = (Worker)myDomain.CreateInstanceAndUnwrap(Assembly.GetExecutingAssembly().FullName, typeof(Worker).FullName);
Console.WriteLine(remoteWorker.RunPlugin());
PrintAssemblies(myDomain);
PrintAssemblies(AppDomain.CurrentDomain);
}
catch(Exception ex)
{
myDomain_UnhandledException(myDomain, new UnhandledExceptionEventArgs(ex, false));
}
finally
{
if (myDomain != null)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Unloading {0}", myDomain.FriendlyName);
Console.ForegroundColor = ConsoleColor.Gray;
AppDomain.Unload(myDomain);
}
}
PrintAssemblies(AppDomain.CurrentDomain);
Console.ReadLine();
}
static void myDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Exception ex = e.ExceptionObject as Exception;
if (ex != null)
Console.WriteLine(ex.Message);
else
Console.WriteLine("A unknown exception was thrown");
}
static void PrintAssemblies(AppDomain domain)
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("Assemblies loaded in domain {0} are:", domain.FriendlyName);
Console.ForegroundColor = ConsoleColor.Gray;
foreach (var item in domain.GetAssemblies())
{
Console.WriteLine(item.FullName);
}
}
}
public class Worker : MarshalByRefObject
{
public Worker()
{
}
public string DomainName
{
get
{
return AppDomain.CurrentDomain.FriendlyName;
}
}
public string RunPlugin()
{
Assembly asm = Assembly.LoadFrom("MyPluginAssembly.dll");
Type pluginType = asm.GetType("MyPluginAssembly.MyPlugin");
object plugin = pluginType.GetConstructor(new Type[0]).Invoke(new object[0]);
return (string)pluginType.GetMethod("Hello").Invoke(plugin, new object[0]);
}
}
}
What you’ll notice is that the first list will show that the remote’s plugin assembly is also loaded in the local appdomain. But once the AppDomain is unloaded, the plugin assembly is gone.
Sunday, June 07, 2009 12:43:50 PM (Pacific SA Standard Time, UTC-04:00)
Programming
Windows Storage Server 2008
This one completely went below my radar. Last month, Microsoft released Windows Storage Server 2008, together with it’s iSCSI target. I’m downloading it now and will post my findings within a few days.
Sunday, June 07, 2009 11:44:28 AM (Pacific SA Standard Time, UTC-04:00)
Storage

Saturday, June 06, 2009
Doing PKI the right way
I’ll be doing a series of articles about PKI, it’s uses and how to set things up in a secure and correct manner. Information in these articles is gathered from various online resources, books and study material. Disclaimer: Though I am confident this information can be used to securely deploy a PKI even in big enterprises, you can use this information at your own risk.
This is the first part of the series, which will talk about setting up a root CA and it’s subordinate CAs. In the next articles we will talk about using this infrastructure to secure mail, encrypt files, secure your web servers, using smart cards for Windows logon and electronically sign your documents. Also, signing macro’s, software, add-ins, and more will be part of all of this. This article is full with abbreviations, though each of them should have at least once mentioned their full meaning.
Setting up a Private Key Infrastructure (PKI)
A PKI needs the following ingredients:
- One root certificate authority
- One or more subordinate certificate authorities
- Active Directory to facilitate in distributing and installing certificates
- A web server
The root CA
The root CA must be installed on a stand-alone machine. This machine must not be connected to the network at any time. Start by installing Windows (Standard Edition recommended), activate Windows by phone, install the latest service pack from a CD or DVD. After that, we’ll need to make some preparations for installing the certificate authority. Make sure the computer name of the machine is unique within your network, even though it’s an offline machine.
Create a text file that is called: “CAPolicy.inf”, and put in the following lines:
[Version]
Signature= "$Windows NT$"
[Certsrv_Server]
RenewalKeyLength=4096
RenewalValidityPeriod=Years
RenewalValidityPeriodUnits=20
[CRLDistributionPoint]
[AuthorityInformationAccess]
This will ensure that in the root certificate, the AIA and CRL fields are suppressed. (More about these in a minute.) Place CAPolicy.inf in your Windows directory and install the CA. Enable the web enrollment option, since we’ll be using the website for creating certificates later.
During the installation of a CA, you’ll need to choose a Cryptographic Service Provider (CSP). Since the root CA (or any CA for that matter) only does signing, no encryption, the MS Strong CSP is sufficient for keys up to 16K, the enhanced CSP has essentially the same parameters. When you want to support CNG (Cryptography Next Generation) certificates, the selection of the CSP is an important one. But note that you might be breaking backwards compatibility if you’re using older clients (i.e. Windows XP SP2 or lower, or Windows Server 2003 and lower.) There is a hotfix though: http://support.microsoft.com/kb/938397
Once the CA is installed, you should have a root certificate that is valid for 20 years.
Configuring the Root CA
The Authority Information Access field in a certificate tells the end user where it can download a certificate which signed the certificate that you are using. For example, John sends you a certificate signed by an unknown certificate authority. You see a signature, but you have no idea who it is… Using a AIA extension you can see where you can obtain that certificate which placed the signature on John’s certificate. You download it and you see that it’s issued by a trusted root certificate authority. Since you trust the root CA, you can trust the signer of John’s certificate and therefore John’s certificate is valid. (There are more things to consider, but are outside of the scope of the AIA.) Without an AIA field you could never have verified John’s certificate.
The problem with an offline computer is that it has no network access. The default AIA field in certificates the root CA will issue will be the computer name of the root CA, which is… unreachable. The same story goes for the CRL Distribution point. The CRL (Certificate Revocation List) is used when certificates are revoked. An OCSP (Online Certificate Status Protocol) responder on the Root CA itself will also not work, because of the same reason: no network access. These fields are therefore important and need to be changed before any certificates are issued.
CA addresses (AIA and CRL) can contain multiple protocols, but I usually stick to http. The reason I do this, is because it’s easy to implement, manage, distribute and why should we make our lives more difficult? This is where the web server comes in. The CRL and the CA Certificate need to be hosted on a web server which anyone (internal in the network and outside of the network) has access to. An example:
On the left you see a picture of one of our intermediate CA’s. The CRL distribution point points to http://cert.thewheel.nl/rootca/The%20Wheel%20Enterprise%20Services%20Root%20CA.crl and if you click that link, you’ll get a CRL file. This is a CRL of our root CA, which is manually copied every month to a web server using an old-style method of either a floppy or a USB disk.
To change these extensions you can use the “Certificate Authority” console, right-click on the server, select properties and select the “Extensions” tab. Next, select the CRL extension and you’ll see a whole lot of items in the list box below, which can look quite intimidating, but don’t worry, it isn’t that geeky.
- The extension starting with: “C:\Windows\system32\…” must have “Publish CRLs to this location” and “Publish Delta CRLs to this location” selected
- Make sure that for the LDAP Extension all checkboxes are unchecked. This is an offline CA, so there’s no LDAP that we can use.
- The default HTTP extension: “http://<ServerDNSName>/…” can be disabled. Uncheck all the checkboxes.
- The default FILE extension: “file://<ServerDNSName>/…” can be disabled. Uncheck all the checkboxes.
- Add a new extension, and type in the following: “http://myserver.mydomain.com/mysubdirectory/<CaName><CRLNameSuffix><DeltaCRLAllowed>.crl” (Without quotes, replace “myserver.mydomain.com/mysubdirectory with the address of your own web server which is everywhere accessible)
- Apply your changes by clicking on the “Apply” button.
Now, we’re doing the same thing for the AIA. Select the AIA extension.
- The extension starting with: “C:\Windows\system32\…” does not have any options you can set
- Make sure that for the LDAP Extension all checkboxes are unchecked. This is an offline CA, so there’s no LDAP that we can use.
- The default HTTP extension: “http://<ServerDNSName>/…” can be disabled. Uncheck all the checkboxes.
- The default FILE extension: “file://<ServerDNSName>/…” can be disabled. Uncheck all the checkboxes.
- Add a new extension, and type in the following: “http://myserver.mydomain.com/mysubdirectory/<CaName><CertificateName>.crt” (Without quotes, replace “myserver.mydomain.com/mysubdirectory with the address of your own web server which is everywhere accessible)
Next, create an empty directory somewhere on the disk and backup your certificate authority to this location. Copy this to some removable media (Floppy, USB flashdrive, etc) and store it in a very secure location. If this data gets compromised, your PKI will be worthless and needs to be rebuilt from scratch. Lastly, we’re going to install the root certificate on all the machines in the network. (That’s the public certificate, not the private key of course!)
Copying the CA Certificate and the Root CA CRL to another computer
First, we need the root certificate, this you can obtain in multiple ways. The easiest way is to go to %windir%\system32\certsrv\certenroll and copy the files to removable media. Next, you can put these files (one CRL, one CRT and a ASP file for Netscape(!) compatibility) This CRT file is the public certificate of you root CA, not a private key so you don’t have to worry that this contains anything that is worth protecting. In fact, it’s quite the opposite, the more people/computers who trust that certificate, the better.
Installing the root certificate on all computers in the Active Directory domain
Now it’s time to get to either your domain controller or your own workstation if you have the group policy management console (GPMC) installed. Open the GPMC, and edit the default domain policy. Select the following path:
- Computer Configuration
- Policies
- Windows Settings
- Security Settings
- Public Key Policies
- Trusted Root Certification Authorities
- Add the root certificate by right-clicking the folder and click “Import”
- Next, open a command prompt and type: “GPUpdate /force” and wait for group policy to be applied.
Verify the root certificate is installed by doing the following steps:
- Open MMC
- Press Ctrl-M to open the “Add or remove snap-ins” dialog
- Add the “Certificates” snapin
- Choose “Computer account” –> “Local computer”
- Add another instance of the “Certificates” snapin
- Choose “My user account”
- Click on OK
- Expand each certificates node
- Check in the “Trusted root certification authorities” folder if your root certificate is there. (Both for the user account and for the computer account)
If they are both there, congratulations. You’ve done the most difficult step in setting up a PKI. The rest is easy :)
Installing a enterprise subordinate certificate authority
Subordinate CAs are CAs that issue certificates to end users. The Root CA doesn’t do this for several reasons, among which are:
- The CA Certificate of the Root CA can never be revoked
- The Root CA is offline, to issue end user certificates from a offline machine is impractical and a administrator’s nightmare.
Therefore, we create a subordinate CA to take away that burden. Subordinate CA’s are installed on domain controllers. Since we use AD, we can use a enterprise subordinate CA and use Certificate Templates to fine-tune our PKI. You’ll need Windows Enterprise Edition on the DC to do this. If you don’t want to use certificate templates (which is a huge benefit sometimes) you can use standard edition. Note that creating certificates for auto enrollment (which means kind-of zero administration) will require Windows Enterprise Edition. My recommendation? Stick with Enterprise Edition, it will save you a lot of time and effort. If you have a DC installed with Standard Edition, you can upgrade this DC to Enterprise Edition. (Both for Windows Server 2003 and 2008). Cross-platform upgrades (i.e. x86 to x64 or vice-versa) are not supported. Only Wipe & Load migrations or side-by-side migrations are possible. If you can, then this might be a good time to get to Windows Server 2008 x64, the 2008 R2 edition (and any future versions of Windows Server) coming in a few months will only support x64. (until 128 bit computing is invented and we’re reaching the 2 Exabyte of memory limitation on a machine
)
The subordinate CA will be a lot easier to install. Add the CA role and enable web enrollment option. I recommend using keys of 2048 bits in length for the intermediate CA. Also here, choose the CSP that best suites your purpose. During the installation you will be asked for the generation of a certificate request. Save the request to disk, we’ll be using the request file later for obtaining the certificate at the root CA.
Once installed, copy the request file to your USB flash drive or floppy, and bring it to the root CA. There you can start the web browser and browse to http://localhost/certsrv and you'll see the website which you can use to request a new certificate. Do the following steps to obtain a certificate for your new intermediate CA:
- Open the certificate authority management console
- Right-click on the CA
- Select All-Tasks –> Submit new request
- Open the request file
- Go to pending requests
- Issue the request
- Go to issued certificates
- Open the issued certificate
- Select the “Details” tab
- Export to a file
- Select the P7B format
- Check “Include all certificates in the certification path if possible”
- Save the file on your removable media
Now you have your certificate for your intermediate CA. Next, you need to install this on your intermediate CA. So you go back to your DC, open the certification authority snap-in and right-click on the CA. Select “Install CA Certificate” and select the certificate on your removable media. If everything went OK your new CA is up-and-running.
Now it’s time to change the extensions, and add some HTTP extensions so that the certificate and CRL can be downloaded via the web. Finally, make sure that the CA publishes the CRL at regular intervals to your web server.
Concluding
I recommend to have at least 2 intermediate certification authorities running, and in larger environments, to load-balance the web server for fault tolerance. (Note that the amount of web traffic is negligible, the goal is fault tolerance, not throughput.) Make sure that the root CA’s private key is well-guarded and treat this like the most important business secret.
If you would be able to factor this number:
30 82 01 0a 02 82 01 01 00 a9 02 bd c1 70 e6 3b f2 4e 1b 28
9f 97 78 5e 30 ea a2 a9 8d 25 5f f8 fe 95 4c a3 b7 fe 9d a2
20 3e 7c 51 a2 9b a2 8f 60 32 6b d1 42 64 79 ee ac 76 c9 54
da f2 eb 9c 86 1c 8f 9f 84 66 b3 c5 6b 7a 62 23 d6 1d 3c de
0f 01 92 e8 96 c4 bf 2d 66 9a 9a 68 26 99 d0 3a 2c bf 0c b5
58 26 c1 46 e7 0a 3e 38 96 2c a9 28 39 a8 ec 49 83 42 e3 84
0f bb 9a 6c 55 61 ac 82 7c a1 60 2d 77 4c e9 99 b4 64 3b 9a
50 1c 31 08 24 14 9f a9 e7 91 2b 18 e6 3d 98 63 14 60 58 05
65 9f 1d 37 52 87 f7 a7 ef 94 02 c6 1b d3 bf 55 45 b3 89 80
bf 3a ec 54 94 4e ae fd a7 7a 6d 74 4e af 18 cc 96 09 28 21
00 57 90 60 69 37 bb 4b 12 07 3c 56 ff 5b fb a4 66 0a 08 a6
d2 81 56 57 ef b6 3b 5e 16 81 77 04 da f6 be ae 80 95 fe b0
cd 7f d6 a7 1a 72 5c 3c ca bc f0 08 a3 22 30 b3 06 85 c9 b3
20 77 13 85 df 02 03 01 00 01
... then Microsoft would have a serious problem. But since they keep their private key secure, it will be long after the time that this key is valid that the secret will be revealed, if ever.
Saturday, June 06, 2009 4:00:49 PM (Pacific SA Standard Time, UTC-04:00)
Security and Cryptography

Friday, June 05, 2009
Installed syntax highlighter
As you might have noticed in the previous post, I’ve installed syntax highlighter. This together with PreCode Snippet allows you to insert code snippets very easily using Live Writer. If you have a coding blog, I can recommend you these tools!
Friday, June 05, 2009 5:36:38 PM (Pacific SA Standard Time, UTC-04:00)
Adding some UI elements with jQuery to an MVC app
One of the requirements that I have on an application that I’m working on is that the user can select a date easily when a textbox has focus. I wanted this to do in such a manner that programmatically this can be done with minimum effort, and that a few extra things are taken into account:
- Nullable dates (i.e. end dates) should be allowed with an empty text box
- Not-nullable dates should default to the date of today
- Multiple date pickers should be possible within the same form
Ingredients
For this to work out, I’ve used the date picker control that’s available at http://jqueryui.com/ Besides that, I’m using ASP.Net MVC 1.0
Creating an extension method for System.Web.Mvc.ViewUserControl
For the view, I’m using an extension method that’s called “DateField”. This allows me to use the date field without having to use things like “RenderPartial” and creating custom models.
This class looks like this:
public static class ViewUserControlDateFieldExtension
{
public static string DateField(this IViewDataContainer control, string fieldName)
{
return DateField(control, fieldName, control.ViewData.Eval(fieldName) as DateTime?, false);
}
public static string DateField(this IViewDataContainer control, string fieldName, bool allowNulls)
{
return DateField(control, fieldName, control.ViewData.Eval(fieldName) as DateTime?, allowNulls);
}
public static string DateField(this IViewDataContainer control, string fieldName, DateTime? value)
{
return DateField(control, fieldName, value, false);
}
public static string DateField(this IViewDataContainer control, string fieldName, DateTime? value, bool allowNulls)
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat("<input type=\"text\" name=\"{0}\" value=\"{1}\" class=\"datepicker\" />", fieldName, GetFieldValue(control, value, allowNulls));
return sb.ToString();
}
private static string GetFieldValue(IViewDataContainer control, DateTime? value, bool allowNulls)
{
if (allowNulls)
{
if (value.HasValue)
return value.Value.ToString("dd-MM-yyyy");
else
return String.Empty;
}
else
{
if (value.HasValue)
{
if (value.Value == DateTime.MinValue)
return DateTime.Now.ToString("dd-MM-yyyy");
else
return value.Value.ToString("dd-MM-yyyy");
}
else
return DateTime.Now.ToString("dd-MM-yyyy");
}
}
}
Next, adding some jQuery script
Adding the script to the master page is easy. Just a few <script> tags and that’s it.
<link href="/themes/redmond/ui.all.css" type="text/css" rel="Stylesheet" />
<script src="/Scripts/jquery-1.3.2.js" type="text/javascript"></script>
<script src="/Scripts/ui/ui.core.js" type="text/javascript"></script>
<script src="/Scripts/ui/ui.datepicker.js" type="text/javascript"></script>
<script src="/Scripts/ui/i18n/ui.datepicker-nl.js" type="text/javascript"></script>
<script type="text/javascript" language="javascript">
// Configure and add a date picker.
$(function() {
$(".datepicker").datepicker({
changeMonth: true,
changeYear: true
});
$(".datepicker").datepicker('option', { dateFormat: 'dd-mm-yy' });
$.datepicker.setDefaults($.extend({ showMonthAfterYear: false }, $.datepicker.regional['nl']))
});
</script>
Finally, use the class
Using the class is as easy as using this little line of code for a date field:
<% = this.DateField("EndDate", true) %>
The result looks like this:

The most nice part? It works in IE7, IE8, Opera, Chrome, FireFox and Safari.
UPDATE: Why use IViewDataContainer
I had a question from someone who wanted to know why I choose to extend IViewDataContainer in stead of WebControl/WebPage. The reason is simple. Both the System.Web.Mvc.ViewPage en System.Web.Mvc.ViewControl implement IViewDataContainer. This makes the interface the easiest target to implement.
Friday, June 05, 2009 5:03:17 PM (Pacific SA Standard Time, UTC-04:00)
MVC | Programming
Giving BitLocker a try
BitLocker can work with an external USB flash drive, so I thought, let’s give this a try. In short, it works fine, I didn’t see any noticeable performance degradation, but it simply does not work for me. There are a few reasons to this, all which I’ll explain below.
The BIOS and the flash drive
My MoBo’s BIOS has a tendency to put the flash drive on top of the list when it considers which device it should use to boot up. This is a pain in the neck, since once I removed the USB drive and I insert it again, my BIOS tends to forget the changes. So the workaround would be pressing F12 during the POST or maybe updating the BIOS… This is the most nasty part of using BitLocker with a USB drive. And putting the RAID array as a secondary doesn’t work either. This is for me the showstopper.
Making duplicates of the USB flash key
This is a good thing of BitLocker, you can easily make a new flash drive using either a new key or simply copy a key from your current one. Also, the password you can put into your vault is a good thing to have. So no comments on this.
You can only encrypt drives on which Windows is installed
You can not encrypt other hard drives in the system. This means that I have 33% of my data protected, while the other is easy to get. This means for me that EFS (Encrypting File System) is a better alternative.
My conclusion
BitLocker has it’s limitations, and with a TPM chip on board things will certainly be a lot better. For notebooks I’d say: Go and use this. For a workstation? Unless you got one hard disk to protect and a TPM chip onboard, use EFS. It’s easier to manage and deploy once you’ve set it up. So I’ll be doing this for the coming hours:

Friday, June 05, 2009 4:25:33 PM (Pacific SA Standard Time, UTC-04:00)

Tuesday, June 02, 2009
Windows 7: RTM next month
In less than 9 weeks from now, Microsoft will be RTM-ing Windows 7. Ina Fried has posted the news about 30 minutes ago on CNet news website.
Official launch date? October 22nd. We’ll have it a few months earlier though :)
Tuesday, June 02, 2009 3:40:46 PM (Pacific SA Standard Time, UTC-04:00)

Monday, June 01, 2009
Putting BING to the test
Bing launched today, which is a new search engine made by Microsoft. Now the question is, is it any better than Google or Live Search?
Let’s put it to the test.
Search number one: My company. Phrase: “The Wheel Automatisering”. I’m looking for my company’s web site.
- Google puts this at number 1.
- Bing puts this at number 1.
Seach #2: A tech phrase which is related with my job, which is programming. The phrase: “system.net.smtpclient”. I’m looking for the MSDN documentation
- Google puts the MSDN documentation at number 1.
- Bing does not put the MSDN documentation on the first page.
Search #3: A phrase of the front page of the English Wikipedia: “tropical cyclone”, I’m expecting the Wikipedia article on the topic.
- Google puts the Wikipedia article right at number 1.
- Bing? The same result as Google.
But this result is more interesting. Bing reports a bunch of wiki’s which Google puts a news item on number 4.
Since I’m using more programming related searches and Bing did not do good on that one, I’ll be using Google for the time to come. But you know what? I started back in the 80’s with Infoseek, Altavista was later, Go.com I also used, Google came around and that’s been my favorite for the last decade, so I guess Bing has to offer something substantially better for me to make the switch.
No doubt that Microsoft will try a lot to make things even better, but popularity of pages is still the most important aspect of getting results, which is Google’s formula up to today.
Monday, June 01, 2009 4:39:11 PM (Pacific SA Standard Time, UTC-04:00)
Articles that don’t tell anything
Sometimes you have an article on a news website, that tells something scary and doesn’t backup it’s claims. Today there’s another one of those published at ZDNet: http://blogs.zdnet.com/security/?p=3476
“20.000 sites hit with drive-by malware attack code”, which does not include:
- Which type of vulnerability was used.
- Which platform(s) where affected.
- Which sites were affected. (I can assume that’s something they don’t want to publish because those companies might get hurt if they did.)
- How those sites got affected.
- Did some hackers get caught?
- Where did these attacks come from?
- …
But in the mean time, webmasters are worried about their sites, and this kind of news does not tell anyone how to protect their sites against these attacks. So please explain me, what is the use of putting an article like this in the wild? The only reason I can think of, it getting more advertising revenue.
So folks at ZDNet: Do your research, post a complete story and don’t go into scare tactics, most people are more than tired of that, including yours truly.
Monday, June 01, 2009 4:21:31 PM (Pacific SA Standard Time, UTC-04:00)

Sunday, May 31, 2009
How to figure out who’s behind a Mafia Wars attack
Anyone who’s playing Mafia Wars online using facebook can easily find out who is attacking or robbing property. An example…
Right-click on the name “Pedro” and copy the link… you get something like: http://apps.facebook.com/inthemafia/remote/html_server.php?…&user=1619114746
The “user” part is important here… Take that number and put it into this URL: http://www.facebook.com/profile.php?id=1619114746
Paste that URL into the browser and voila!
Nice to know you, Richard Burt :)
So you’re not anonymous in Mafia Wars, and no, I don’t hold any grudges because it’s just a game, and robbing is just a part of it.
Sunday, May 31, 2009 3:11:20 PM (Pacific SA Standard Time, UTC-04:00)

Friday, May 29, 2009
My new PC Components
Yesterday night I’ve installed my new PSU and one of my new graphics cards. The other one will have to wait, because my current Mobo has a bit of a problem. Guess where the SATA connectors are? Yep, right below the card, which means I either yank out 3 disks or I replace the board if I want to have my new graphics card installed.
This is a big disappointment, but that does not stop me for looking a bit further, it seems that they sell DFI boards at PCFactory. I’ll order a DK 790FXB M2RS which has the SATA ports on the side of the board and has all the nice over clocking features that you only can dream of. It’s just too bad they don’t sell the “H” model, which includes a better heat sink and heat pipe. So I guess a few extra ventilators will have to cool down the system.
Besides this, the new PSU does an outstanding job, as well as my new card. I’ve tried Call of Duty 5 and with everything maxed out, it simply runs fluently. One word: Fantastic!
So this board will be my new one:
Time to place another order… board number 4. (One ECS died after 8 months of use, 2 are still in service but one is replaced because of this mess.)
Update: Since this board doesn’t have a heat pipe, and the cooling is kind of important when you’re working with a 3 Ghz processor and 2 huge video cards, I’m still looking a bit further so see if there are some alternatives.
Friday, May 29, 2009 9:41:39 PM (Pacific SA Standard Time, UTC-04:00)

Thursday, May 28, 2009
A closer look at my new AT HD2870 cards
The first question you might have: Why did you buy 2 of these monsters? Reason: I have 3 monitors. And not just simple monitors, but these babies:

Each has a resolution of 1920 * 1200, which brings the total up to 6.912.000 pixels. My current HD2600XT and HD2600 PRO are simply not cutting it. I’ve got poor performance with Windows Aero and even worst with Windows Presentation Foundation. Gaming is out of the question, it simply stutters too much and I get shot dead even before I can aim… (which does not have anything to do with my gaming skills!)
So that answers the “Why?” question. Now let’s take a look at the rest. The HD4870 can be crossfired, but once you do that, you have only one monitor to work with. So what I want is that my primary monitor will do the heavy lifting (the one in the middle), and the other 2 on the sides are used with ATI Surround View. ATI’s CCC (Catalyst Control Center) is for this a big help. You can use CCC for enabling and disabling Crossfire. Simply make 2 profiles, one with Crossfire enabled and one without Crossfire and with 3 monitors enabled. Guess what the result is? Excellent performance for my programming work, and even better for gaming. Now that would be ideal, wouldn’t it? This is what I’m trying to accomplish, I’ll know if it works once my system is installed.
The cards
When opening the box, this is what you get. Crossfire cable, power cables which you can use if you PSU doesn’t have the right connectors, a DVI2HDMI and DVI2VGA connector, Composite video cable, SVHS, a CD and a little booklet. Oh, and the video card of course ;)
The card is quite big. It will probably be the biggest video card I’ve seen, but since I’m out of the hardware business a long time now, that doesn’t say much. It uses 2 slots, one for ventilation, the other for connecting the screens.
This heat sink is no joke…
The card requires 2 PCI-E power connections.
With 1 GB of GDDR5 memory, it should make my PC considerably faster. The rest is already in place (1 Quad core 4 Ghz Proc, 8 GB memory and 2 RAID0 sets on SATA2 hard disks), this is just the final piece of the puzzle.
Next post within a few hours, with some more photos.
Thursday, May 28, 2009 8:20:22 PM (Pacific SA Standard Time, UTC-04:00)
A closer look at my new PSU

I have never had a modular PSU with these kind of connectors, it was for me kind of surprising to see how these cables are all put together.
First, I wanted to make sure that my PSU supports 230V. In the manual it states: “Make sure the correct input voltage is selected and change the switch if necessary.” I’m looking for a switch but I can’t find it anywhere. On the side sticker it says: “115V-230V 60/50Hz”, so it seems that this PSU does figure it out by itself. I wanted to be absolutely sure though, so I looked it up online. There the specs of my specific model said: “Full range active PFC”… which kind of gives me a hint that this should be the case. Looking a bit further, yep. An “Full range active PFC” means actually: “Full range active power factor correction”, which does figure out what the input voltage is and corrects it when needed. When I would have 160V here, it still would work. (I’ve got 220V)
So it’s safe to plug it into my outlet here. Now the next step, the cabling. This PSU comes with 8 cables to connect to peripherals, which each include 2 or more connectors to connect to your devices and one connector for the PSU. The PSU has 4 connectors that are reserved for video cards, and 4 for other appliances. The motherboard cables are hard-wired.
One cable contains for example 4 SATA connectors and another one contains a PCI-E Graphics connector. In total you’ll have enough to connect 2 full-blown heavy-duty graphics adapters without a problem.
The nice part of a modular PSU is that you only have to connect the cables you actually need. Other cables you can leave in the box and those do not clutter up your system (and prevent proper cooling.) There’s a huge ventilator on that thing. I’ve never seen a ventilator of that size before, it is simply as wide as possible. That will do the job of cooling. It’s quite big… did I mention it’s big? It’s also quite heavy, a 4.1 Kg of metal.
I’ve been reading some reviews (before I bought it) and I’m curious to see it in action. In less than 2 hours my friend arrives here and we’ll build this machine.
About cooling, I’ve got a big case, a side-fan and a big front fan. I hope it is enough.
Can I recommend this PSU? I’ll know once it is installed. Time for some open-heart surgery :)
Thursday, May 28, 2009 7:44:45 PM (Pacific SA Standard Time, UTC-04:00)
Jippie, just got my things :)
I' just received my 2 video cards and the power supply I ordered. I have never seen anything remotely like it, what a huge devices.
My video cards looks like this:
These Radeon HD4870 cards are fast and also consume a lot of power. So I bought the right power supply to go with it:
This beast does a 1000W, has an amount of cables I’ve never seen come out of a PSU and – most importantly – does 220V/50 Hz :)
Tonight I’m going to build my machine, and I’ll report back on how it went. Can’t wait!
Thursday, May 28, 2009 5:55:20 PM (Pacific SA Standard Time, UTC-04:00)
This is weird…
I’m getting a YSOD (Yellow Screen of Death) on this line of code: (Line 19)
Line 17: <td valign="top">Geslacht:</td>
Line 18: <td>
Line 19: <% = Html.RadioButton("Gender", "M", Model.Gender == 'M') %> Man<br />
Line 20: <% = Html.RadioButton("Gender", "F", Model.Gender == 'F') %> Vrouw<br />
Line 21: </td>
Model is not null.
[NullReferenceException: Object reference not set to an instance of an object.]
System.Web.Mvc.HtmlHelper.GetModelStateValue(String key, Type destinationType) +63
System.Web.Mvc.Html.InputExtensions.InputHelper(HtmlHelper htmlHelper, InputType inputType, String name, Object value, Boolean useViewData, Boolean isChecked, Boolean setId, Boolean isExplicitValue, IDictionary`2 htmlAttributes) +328
System.Web.Mvc.Html.InputExtensions.RadioButton(HtmlHelper htmlHelper, String name, Object value, Boolean isChecked, IDictionary`2 htmlAttributes) +193
System.Web.Mvc.Html.InputExtensions.RadioButton(HtmlHelper htmlHelper, String name, Object value, Boolean isChecked, Object htmlAttributes) +67
System.Web.Mvc.Html.InputExtensions.RadioButton(HtmlHelper htmlHelper, String name, Object value, Boolean isChecked) +16
ASP.areas_agencies_views_contact_contactedit_aspx.__RenderContent1(HtmlTextWriter __w, Control parameterContainer) in c:\VSP\Boulder\The Wheel Ict CV\TheWheel.IctCv.Web\Areas\Agencies\Views\Contact\ContactEdit.aspx:19
System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) +256
System.Web.UI.Control.RenderChildren(HtmlTextWriter writer) +19
System.Web.UI.Control.Render(HtmlTextWriter writer) +10
System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter) +27
System.Web.UI.Control.RenderControl(HtmlTextWriter writer, ControlAdapter adapter) +99
System.Web.UI.Control.RenderControl(HtmlTextWriter writer) +25
ASP.views_shared_site_master.__Render__control1(HtmlTextWriter __w, Control parameterContainer) in c:\VSP\Boulder\The Wheel Ict CV\TheWheel.IctCv.Web\Views\Shared\Site.Master:25
System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) +256
System.Web.UI.Control.RenderChildren(HtmlTextWriter writer) +19
System.Web.UI.Control.Render(HtmlTextWriter writer) +10
System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter) +27
System.Web.UI.Control.RenderControl(HtmlTextWriter writer, ControlAdapter adapter) +99
System.Web.UI.Control.RenderControl(HtmlTextWriter writer) +25
System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) +134
System.Web.UI.Control.RenderChildren(HtmlTextWriter writer) +19
System.Web.UI.Page.Render(HtmlTextWriter writer) +29
System.Web.Mvc.ViewPage.Render(HtmlTextWriter writer) +59
System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter) +27
System.Web.UI.Control.RenderControl(HtmlTextWriter writer, ControlAdapter adapter) +99
System.Web.UI.Control.RenderControl(HtmlTextWriter writer) +25
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +1266
Anybody got any ideas?
UPDATE: It had to do with the fact that the field validation caused problems when multiple fields have the same name.
Thursday, May 28, 2009 1:06:58 AM (Pacific SA Standard Time, UTC-04:00)