Tuesday, February 22, 2011

Silverlight : Could not load file or assembly 'System.Windows, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e' or one of its depend

Very irritating!

and very similar to here:
http://bartwullems.blogspot.com/2010/08/could-not-load-file-or-assembly.html


Solved as follows:

cd C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\Silverlight\v4.0

gacutil /i System.Windows.dll

gacutil /i System.Core.dll

Friday, August 27, 2010

Net.Tcp WCF requires clientaccesspolicy.xml be available from IP, not hostname

Testing a new Net.Tcp WCF service, I got the following error:

"Could not connect to net.tcp://X:4502/XService. The connection attempt lasted for a time span of 00:00:00.4270427. TCP error code 10013: An attempt was made to access a socket in a way forbidden by its access permissions.. This could be due to attempting to access a service in a cross-domain way while the service is not configured for cross-domain access. You may need to contact the owner of the service to expose a sockets cross-domain policy over HTTP and host the service in the allowed sockets port range 4502-4534."

Although this is a very common error, in our case, it was not fixed by the obvious solutions:

1. clientaccesspolicy.xml was already available. I verified that through the browser.
2. clientaccesspolicy.xml already had the correct contents allowing port 4502.

It turned out that while clientaccesspolicy.xml was available via our server hostname, it was NOT available via the server IP address.

Even if the Silverlight client is configured to access a net.tcp WCF service using a valid DNS name, it still uses the IP address of that DNS name to load the clientaccesspolicy.

This happens EVEN IF it has already loaded the very same clientaccesspolicy.xml through the DNS name.

In our case at least, IIS7 by default does not allows access by IP for a site that has already been configured for for a DNS name.

So I added a new site in IIS Manager, bound to the IP address, pointing to the same folder already containing our clientaccesspolicy.xml file.

But, this new site must be bound to the internal IP (e.g. 192.168.1.xxx), NOT the external IP (e.g. 88.77.66.55).


After I discovered the problem I found this:

http://blogs.msdn.com/b/silverlightws/archive/2010/04/09/policy-file-for-nettcp.aspx

Wednesday, August 25, 2010

Net.Tcp WCF service requires 'Integrated' managed pipeline mode, not 'classic' mode

We built and successfully tested a Net.Tcp WCF service. But when deploying it to an off-site server for further testing, we discovered the IIS worker process was crashing.

In the event log, we got plenty of these:


Source: ASP.NET 4.0.30319.0
EventID: 1088
Description: 0x8000ffff Catastrophic failure


and some of these:


Faulting application name: w3wp.exe, version: 7.5.7600.16385, time stamp: 0x4a5bcd2b
Faulting module name: unknown, version: 0.0.0.0, time stamp: 0x00000000
Exception code: 0xc0000005
Fault offset: 0x00000000
Faulting process id: 0xfe8
Faulting application start time: 0x01cb429f60c2c986
Faulting application path: C:\Windows\SysWOW64\inetsrv\w3wp.exe
Faulting module path: unknown
Report Id: f85bf6d3-ae92-11df-a403-00219b00a9ca


We had to issue an 'iisreset' command from command line to bring it back.

It turns out, the offsite servers were running our application using a 'Classic' mode app-pool. But during development, we used 'Integrated' managed pipeline mode.

Changing the offsite servers to 'Integtated' seemed to fix the problem.

Thursday, August 12, 2010

ExecuteReader: Connection property not initialized

This is an inaccurate error message!!

Despite what the error message says, the following error can be caused by not setting the 'CommandText' property of the SqlCommand object:

System.InvalidOperationException: ExecuteReader: Connection property has not been initialized.

I noticed this while working with transactions.

In my case it was NOT caused by the 'Connection' property

Friday, June 18, 2010

Cygwin SSHD, Remote Tunnel, GatewayPorts

When opening a remote tunnel over SSH, I need to allow clients on machines other than the SSHD host access the port that has been opened.

To do this, the client needs to specify this option. e.g. in putty, set the 'Remote ports do the same' option.

AND

the SSHD server needs to have 'GatewayPorts' enabled in /etc/sshd_config

Thursday, June 17, 2010

Subversion: Trimming old commits, keeping revision numbers intact.

Our repository is getting quite large. Some time ago, we reorganised our repository, and none of the history before that reorganisation is really that important.

So, I decided to do a 'dump' of the repository from the earliest required revision to HEAD, and the load that into a fresh repository.

But I got the following warnings:
"Referencing data in revision [X], which is older than the oldest"
and
"Loading this dump into an empty repository will fail."

So I retried this a few times, moving back the 'start' revision until I no longer got this error. Luckily I didnt have to go back much further.

I then did a 'load' cammand of this new dump back into a new repository.

Next thing I noticed was that this new repository, while functionally correct, had different revision numbers. But the old revision numbers are referenced in our revsion tracking system, and in comments throughout out the version history.

How do I load back my dump file, with a starting revision matching the original repository?

I found I could put together a tiny script that inserts a series of trivial commits to the repository, filling in the required version numbers. Then when loading in my dump file, it's commits match the revision number of the original repository.

But since the new repository is not empty when loading the dump file, I need to set the UUID of the new repository to match the old repository, using --force-uuid

Its not the most elegant solution, but seems to work.

The following are the commands I used:

1.
svnadmin dump \SVN\ROOT -r 1282:HEAD > ROOT_1282.dump

2.
svnadmin create \SVN\ROOT2

3.
svn co file:///c:/SVN/ROOT2 ROOT2_WC

4.
echo 0 > ROOT2_WC\zzz

5.
svn add ROOT2_WC\zzz

6.
# NOTE: the following commits from r1 to r1280, since r1281 happens
# in step 8. Then the dump file starting revision (original r1282)
# matches the next revision in this new repository.
for /L %n in (1,1,1280) do (
echo %n > ROOT2_WC\zzz
svn commit ROOT2_WC\zzz -m "empty commit replaces original")


7.
svn delete ROOT2_WC\zzz

8.
svn commit ROOT2_WC -m "removing dummy file used for empty commits"

9.
svnadmin load --force-uuid ROOT2 < ROOT_1282.dump

Friday, May 14, 2010

SQL Server Transaction Log too big...

USE MyData
GO
DBCC SHRINKFILE(MyData_log, 1)
BACKUP LOG MyData WITH TRUNCATE_ONLY
DBCC SHRINKFILE(MyData_log, 1)
GO

Wednesday, April 21, 2010

What process opened a port on windows?

To see the process id of all open ports:
netstat -a -n -o

To the the process name of a particular process id:
tasklist /svc /FI "PID eq 2856"

I should really write a script to combine these...

Wednesday, March 10, 2010

Windows 7 Firewall, Limit SSH Access to Ireland only

I've cygwin SSHD running on one of my windows 7 machines. I've noticed connection attempts for places all over the world. I'd rather restrict access a bit, in case they are attacking an exploitable flaw, or one of my password are too weak ( I must set up key-only login auth)

Now that Windows 7 has a much improved firewall, I can now add rules that allow inbound access to port 22 to a limited set of remote IP addresses.

To limit it to Ireland only, for example, I looked up the full range of Irish IP addresses using this site: http://www.countryipblocks.net/

Then I ran the following from the command line (run as Administrator):

netsh advfirewall firewall add rule name="SSHD IN Ireland Only" dir=in localport=22 protocol=TCP action=allow remoteip=62.9.0.0/16,62.17.0.0/16,62.40.32.0/19,62.77.160.0/19,62.231.32.0/19,....

The full list of subnets is quite long, and I don't know what is the maximum number of entries allowed. Indeed, neither do I know the performance impact on networking in general, if any, of a large number of entries. If they've built the firewall properly, the impact should be negligible on unrelated connections.

Tuesday, February 23, 2010

DDOS, URLScan, Disable IIS Logging

We have had to deal with a distributed denial of service attack lately.

Without getting into the details of the attack itself, it turned out, at least initially, that the bots could be identified by a relatively small number of user-agent strings.

Googling the odder looking useragents showed us examples of similar attacks in the past using the same bot software. This indicated, as seems to be quite normal, that the infected machine are spoofing their IPs.

While our hosting provider was looking at the issue at a network level, made very difficult by the spoofed IPs, I tried an IIS host-level solution.

1.
I installed URLScan 3.1
http://www.iis.net/expand/UrlScan

2.
I then edited the site-wide URLScan.ini in C:\WINDOWS\system32\inetsrv\urlscan

Changing:
RuleList=
to
RuleList=DenyUserAgent

[DenyUserAgent]
DenyDataSection=AgentStrings
ScanHeaders=User-Agent

[AgentStrings]
Mozilla/5.0%20%28Win.....


where the AgentStrings lists the 'escaped' user-agent string that should be blocked.


3.
Given the volume of entries in the logs, I also had to disable both the logging done by URLScan, as well as IIS's own logging of blocked requests.


3a.
So I flipped the value of EnableLogging in URLScan.ini to '0'

3b.
And then executed the following two commands to disable logging of only the specific /Rejected-By-UrlScan pseudo-url in IIS logs:

CSCRIPT %SYSTEMDRIVE%\Inetpub\AdminScripts\adsutil.vbs CREATE W3SVC/1/ROOT/Rejected-By-UrlScan IIsWebFile
then
CSCRIPT %SYSTEMDRIVE%\Inetpub\AdminScripts\adsutil.vbs SET W3SVC/1/ROOT/Rejected-By-UrlScan/DontLog

4.
Restarted the 'World Wide Web Publishing Service'.

Note:
URLScan does a substring match of entries listed in a custom rule's DenyDataSection. This would make it possible to block attacks if, for example, the attacker had a typo in one of the request headers. So you dont need to just match a complete header string.

But it does not allow more complicated matching, e.g. using regular expressions. If you are looking for the flexibility of Apache's various modules and directives, URLScan is not the answer.


Conclusion:
This solution is only suitable for the most small-scale attacks. The attacker only has to update the user-agent strings. Or instead just increasing attack traffic would max-out the CPUs of the web servers, since it has to go through extra effort to parse the request headers. Increasing attack traffic could kill servers through maxing out the bandwidth available, or the connection limit. Host-based mitigation techniques like this are, in general, going to be ineffective against botnet attacks.

Friday, January 29, 2010

Encrypted Web.config on IIS 6.0, Win2k3

1.
created identity.aspx containing only the following:

<%@ Page Language="C#" %>
<%
Response.Write(System.Security.Principal.WindowsIdentity.GetCurrent().Name);
%>

In a browser, saw that the identity was
NT AUTHORITY\NETWORK SERVICE


2.
cd C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727


3.
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727>aspnet_regiis -pa "NetFrameworkConfigurationKey" "NT AUTHORITY\NETWORK SERVICE"
Adding ACL for access to the RSA Key container...
The RSA key container was not found.
Failed!


4.
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727>aspnet_regiis -pc "NetFrameworkConfigurationKey" -exp
Creating RSA Key container...
Succeeded!


5.
Tried step 3. again...

C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727>aspnet_regiis -pa "NetFrameworkConfigurationKey" "NT AUTHORITY\NETWORK SERVICE"
Adding ACL for access to the RSA Key container...
Succeeded!


6.
I have two websites, on different ports, both on the root URL /, so to distinguish them when encrypting the connection strings, I uses the site ID ( Identifier field in IIS Manager Web Sites list),

C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727>aspnet_regiis -pe "connectionStrings" -app "/" -site 1
Encrypting configuration section...
Succeeded!

C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727>aspnet_regiis -pe "connectionStrings" -app "/" -site 219934440
Encrypting configuration section...
Succeeded!


7.
I verified in a text editor the Web.config sections had been changed, and also that the running application was still able to read the connection strings.


8.
I did the same for the machineKey:

C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727>aspnet_regiis -pd "system.web/machineKey" -app "/" -site 219934440
Decrypting configuration section...
Succeeded!



9.
I tested decrypting the sections back to the originals:

C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727>aspnet_regiis -pd "connectionStrings" -app "/" -site 1
Decrypting configuration section...
Succeeded!

C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727>aspnet_regiis -pd "connectionStrings" -app "/" -site 2054359653
Decrypting configuration section...
Succeeded!




All taken from:
http://msdn.microsoft.com/en-us/library/dtkwfdky.aspx
http://social.msdn.microsoft.com/Forums/en/clr/thread/087df87f-8fb5-4e54-a57b-0bbdbc544c4f
http://forums.asp.net/p/960412/1423554.aspx#1423554

Friday, January 22, 2010

Semi-Transparent Windows

Sometimes I work on the command line, or am editing some file in a text editor. But I want to look at one window while I type in another. Even with my two screens, windows must sometimes overlap, but when this is necessary a semi-transparent foreground window can be handy, so the window behind can still be read.

Yes, Aero in windows lets your windows' border be semi-transparent. But it's only a thin border, and you still cant read what's behind as the background is blurred. I really dont understand the usability advantage of this feature. Seems a bit useless to me.

There's also the 'Glasser' extension for Firefox that makes Firefox's toolbars transparent in a similar way. But that only adds a bit of consistency, without much of a benefit.

Slightly more useful, is 'Glass CMD for Vista' that makes cmd.exe semi-transparent, but again, the background is blurred so you cant read what is behind. There is also 'Glass Notepad'.

What about disabling blur? It is possible with a registry hack, or by replacing DLLs on Windows 7. Neither of theas seem like a very clean solution.

Then I found Glass2k. And it even works on Windows 7 x64! I just press Ctrl-Shift-[1 to 9] to vary the transparency. And there is no blur. Perfect.

Tuesday, November 24, 2009

Convert VB.Net to C#

Sometimes I see code snippets online written in VB.Net. Yes, its not hard too work out what the code it doing, but it is still slower than working with C# which I am much more familiar with.

I found this:
http://www.developerfusion.com/tools/convert/vb-to-csharp/

It translates between the two languages.

Friday, November 20, 2009

find .png files larget than 64k, and copy to a temp directory

find /cygdrive/c/ -size +64k -name '*.png' -print0 | xargs -0 -n1 -I % cp % /cygdrive/c/temp/images/png/

Wednesday, November 18, 2009

Recursive Methods, Stack Overflow, IIS & FXCop

Had some serious issues lately around crashing IIS. The logs indicated a Stack Overflow Exception, error code 0x800703E9.

But it wasn't obvious what caused this, since no recent changes seemed to be the culprit, and developers seemed to be unaware of any recursion in our code.

Unfortunately, there is far too much code to aimlessly search through.

I identified the following possible cases where we may have introduced recursion:

1. Intended recursion, a method directly calling itself somewhere
2. Possibly intended recursion, a method indirectly calling itself via another method.
3. Unintended recursion when an overloaded method calls itself instead of one of the other overloads because of too many or few arguments.
4. Unintended recursion because of a typo in a property getter or setter
5. Unintended recursion because of a missing (T) cast when calling 'static bool T.Equals( T x, T y)' inside an 'override bool Equals(object obj)'
6. .Net library classes throwing this exception.


More info:

1.
This is straight forward enough... a method somewhere has a flaw either in the logic that identifies stopping conditions causing infinite recursion, or the depth of recursion depends on the inputs, and the method is processing inputs larger than the developer considered.

2.
See above.


3.
Overloading, without being careful with the arguments can mean a method calling itself instead of the other overload, e.g.

public class X
{
public int A( int f)
{
// infinite recursion - developer should have
// written 'return A(f, 0);'
return A(f);
}

public int A( int f, int g)
{
return f + g;
}
}



4.
The following two properties cause infinite recursion. The first has a typo in the getter, the second has a typo in the setter. (the case is incorrect)

private string abc;
public string Abc
{
get { return this.Abc; }
set { this.abc = value; }
}

private string xyz;
public string Xyz
{
get { return this.xyz; }
set { this.Xyz = value; }
}


5.
It is common practice to implement public override bool Equals(object obj) in classes that are used in collections. It is also not uncommon to implement public static bool Equals(T a, T b) in the same classes too (e.g. the System.string class)

However, if the overridden method directly calls the static method without both of it's arguments cast to the correct type (T), then recursion could result, e.g.
public class T
{
public override bool Equals(object obj)
{
return T.Equals(this, obj);
}

public static bool Equals(T a, T b)
{
return true;
}

}


The above code will cause infinite recursion, since the first method is actually calling static bool object.Equals(object a, object b), not static bool T.Equals(T a, T b) which will then call bool T.Equals( object obj) on each argument.

To fix this, object obj must be cast to type T before calling the static method:
public class T
{
public override bool Equals(object obj)
{
return T.Equals(this, (T)obj);
}

public static bool Equals(T a, T b)
{
return true;
}

}



6.
Possibly Linq to SQL issue?
http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=355026


But how to identify any methods like this in a large library of code? FXCop to the rescue.

This is my first time using FXCop, but I couldnt find any existing rules that would identify these cases, so I set about writing some custom rules ( Tutorial )

A. Identifying direct recursive methods ( covers cases 1, 3 & 4 above)

I based my custom rule on the "Callees" example class here, with the following 'Check' implementation:
public override ProblemCollection Check(Member member)
{
Method method = member as Method;
if (method != null)
{
string unmangledName = method.GetUnmangledNameWithTypeParameters();

IList callees = Callees.CalleesFor(method);
foreach (Method c in callees)
{
if (string.Equals(c.FullName, method.FullName) && string.Equals(c.GetUnmangledNameWithTypeParameters(), unmangledName) )
{
Resolution res;
if (c.Name.Name.StartsWith("get_") || c.Name.Name.StartsWith("set_"))
{
res = this.GetResolution();
res = new Resolution(string.Format("Check property name typo. {0}", res.Format), new string[] { c.FullName } );
}
else
{
res = this.GetResolution(new string[] { c.FullName });
}
Problems.Add( new Problem(res) );
}
}
}
return this.Problems;
}



B. Identifying indirect recursive methods ( covers case 2 above)

Here's my implementation:
public override ProblemCollection Check(Member member)
{
Method method = member as Method;
if (method != null)
{
//string unmangledName = method.GetUnmangledNameWithTypeParameters();
string fullName = method.FullName;
if (!string.IsNullOrEmpty(fullName) && !fullName.StartsWith("Microsoft.") && !fullName.StartsWith("System."))
{
List methodStack = new List();
methodStack.Add(fullName);

IList callees = Callees.CalleesFor(method);

TraverseCallees(methodStack, callees);
}
}
return this.Problems;
}


private void TraverseCallees(List methodStack, IList callees)
{
foreach (Method c in callees)
{
//string unmangledName = c.GetUnmangledNameWithTypeParameters();
string fullName = c.FullName;
if (!string.IsNullOrEmpty(fullName) && !fullName.StartsWith("Microsoft.") && !fullName.StartsWith("System."))
{
if (methodStack.Contains(fullName))
{
// only match against the head of the stack, since all methods will be processed as the head once
if (string.Equals(methodStack[0], fullName))
{
// only show indirect calls
if (methodStack.Count > 2)
{
StringBuilder callStackDescription = new StringBuilder();

//bool logStack = false;
foreach (string methodFullName in methodStack)
{
//if (!logStack && methodFullName.Equals(fullName))
//{
// logStack = true;
//}

//if (logStack)
//{
callStackDescription.AppendFormat("{0} -> ", methodFullName);
//}
}
callStackDescription.AppendFormat("{0}", fullName);

Resolution res = new Resolution(GetResolution().Format, new string[] { callStackDescription.ToString() });

Problems.Add(new Problem(res, c));
}
else
{
// ignore recursion, where it is a method directly calling itself
}
}
}
else
{
methodStack.Add(fullName);

IList nextCallees = Callees.CalleesFor(c);

TraverseCallees(methodStack, nextCallees);

methodStack.RemoveAt(methodStack.Count - 1);
}
}
}
}



C. Overridden T.Equals Calling Object.Equals ( covers case 5 above )

public override ProblemCollection Check(Member member)
{
Method method = member as Method;
if (method != null)
{
string fullName = method.FullName;
if (!string.IsNullOrEmpty(fullName) && !fullName.StartsWith("Microsoft.") && !fullName.StartsWith("System."))
{
// check of our 'Equals' overrides the defualt 'object.Equals(object obj)', since that may be called by 'static object.Equals(object, object_'
if (string.Equals(method.OverriddenMethod == null ? null : method.OverriddenMethod.FullName, "System.Object.Equals(System.Object)"))
{
IList callees = Callees.CalleesFor(method);

foreach (Method c in callees)
{
if( c.IsStatic && string.Equals( c.FullName, "System.Object.Equals(System.Object,System.Object)") &&
c.Parameters.Count == 2 &&
string.Equals( c.Parameters[0].Type.FullName, "System.Object" ) &&
string.Equals( c.Parameters[1].Type.FullName, "System.Object" ))
//TODO: also check the the VALUE of one of the arguments is really of the same type as the parent caller method
{
Problems.Add(new Problem(GetResolution(), c));
}
}
}
}
}
return this.Problems;
}



Sure enough, my custom rules found new examples of cases 1 and 3. And I am aware of cases 4 & 5 happening in the past, although luckily they were fixed during development.

Monday, October 19, 2009

HTTPS Client Certificate Auth to Redmine and Subversion

Internally, we have been using Redmine (www.redmine.org) for managing development projects, and well as subversion for version control.

The time has come for providing access to both of these from the Internet. However, we do not want anyone who is not unauthorised to do so to be poking around the servers we make available.

The solution is to make the applications available over HTTPS, and to require the correct client certificates be installed on the client browsers, before a connection can be made.


A. Redmine Path.
Initially, Redmine was running through it's own webserver on http://server:3000/
However, we dont want to have Redmine available from a root url like this, but instead have to run from some sub-URI, e.g. .../redmine/, since other paths will refer to other applications.

Do do this, I did as was described in many other places on the Internet(http://www.redmine.org/wiki/1/HowTo_Install_Redmine_in_a_sub-URI), I added the following line to the end of \config\environment.rb

ActionController::AbstractRequest.relative_url_root = "/redmine"

Unfortunately, after restart the CSS and Javascript was not found, giving me an ugly, mostly white page. This was not something I found mentioned much, and the only solution I found was the following: to move everything inside Redmine's \public\ directory into \public\redmine\ to match the sub-URI path expected.

B. Apache and HTTPS

Below is a subset of the configuration directives used to enable HTTPS access. Anything not listed is a default setting in the example provided httpd-ssl.conf. The certificate files listed below were created in my previous post on using XCA to create various types of certificates.


<VirtualHost 192.168.1.250:443>

ServerName www.mydomain.com:443

SSLEngine on

# PEM encoded certificate
SSLCertificateFile "c:/Program Files/Apache Software Foundation/Apache2.2/conf/www.mydomain.com.pem"

# Where to find CA certificates for client authentication
SSLCACertificateFile "c:/Program Files/Apache Software Foundation/Apache2.2/conf/MyCA.crt"

# To force clients to use Client Certificates
SSLVerifyClient require
SSLVerifyDepth 2

...
...

</VirtualHost>


I added the following section to the above to provide access to Redmine:


<Location /redmine>
RequestHeader set X_FORWARDED_PROTO 'https'
ProxyPass http://localhost:3000/redmine
ProxyPassReverse http://localhost:3000/redmine
</Location>


Note: the above allows anyone with a valid trusted certificate (signed by 'MyCA' CA) to connect. Of course, they should not be able to get past Redmine's login page without a valid login. This is the same Basic Auth as we have been using in the office, except external access wraps it all inside a HTTPS connection.

We have allowed limited to our Redmine server to external testers, however they should have no access to our Subversion repository.

So the URL to our subversion, say /svn/ should be more restrictive than for Redmine - a trusted client certificate is still necessary, but it is not enough. The client certificate needs to have certain properties to be granted access to Subversion.

In our case, any client certificates that should be granted access to Subversion, must have 'OurCompany' set correctly in the Organisation field of the client certificates Distinguished Name. Any other client certs, e.g. those of external testers, must have the Organisation field set to something else.

The following snippet fulfils these requirements, where the subversion repository would be in c:\SVN\.


<Location /svn/>
SSLRequire %{SSL_CLIENT_S_DN_O} eq "OurCompany"

DAV svn
SVNPath C:/SVN/
AuthzSVNAccessFile "C:/Program Files/Apache Software Foundation/Apache2.2/conf/svn-acl"
AuthUserFile "C:/Program Files/Apache Software Foundation/Apache2.2/conf/svn-auth-file"

#SSLOptions +FakeBasicAuth +StrictRequire
#SSLUserName SSL_CLIENT_S_DN_CN

AuthName "Subversion"
AuthType Basic
AuthBasicProvider anon
Anonymous "*"
Require valid-user

<limitexcept>
Require valid-user
</limitexcept>

</Location>



The above snippet restricts access based on the particular client certificate in use, however once access have been granted, it still uses Basic Auth for Subversion authentication, with all subversion users configured in svn-acl. This is identical to the non-https internal access used in the office.

Ideally, the client certificate itself could be used to provide those authentication details, without needing a separate Basic Auth login after the HTTPS connection has already been negotiated.

However, this proved difficult. First, I enabling the following two lines (commented out in the above snippet):


SSLOptions +FakeBasicAuth +StrictRequire
SSLUserName SSL_CLIENT_S_DN_CN


The effect of these is to use the client certificate's Common Name as the username for subversion authentication. It then fakes the basic auth process with this username. Details of how to set up subversion with Basic Auth are only a quick search away.

The problem with the above is that the actual username coming from the client certificate is "CN=/bob" instead of "bob", so if I set the certificate Common Name to "Bob", and Bob has an internal username called "Bob", subversion logs for example will not have the same username when commits are made inside and outside the office by the same person.

Creating my own Root CA, HTTPS Server and Client certificates, with XCA

The following assumes XCA 0.7.0

Prelim:
Before doing anything, you need to create the XCA database. Pick a strong password.


A. To create the Root Certificate

1. Select the 'Certificates' tab.
2. Click on 'New Certificate' on the left side.

3. Select the 'Source' tab.
4. Signing -> 'Create a self signed certificate with the serial 1'
5. Signature algorithm -> 'SHA 1' ( I read something about older system having problems with the better 'SHA 256' )
6. Template -> '[default] CA'. Click Apply!! Do not forget to apply.

7. Select the 'Subject' tab.
8. At the very least, fill in 'Internal Name', 'Common name', e.g. 'MyCA' for both.
9. Private Key -> click 'Generate a new key'

10. Select the 'Extensions' tab
11. Make sure the 'Time range' is 10 years or so. If changed, be sure to 'Apply'

12. Select the 'Key Usage' tab.
13. If you clicked 'Apply' to CA template (step 6), you should see 'Certificate Sign' and 'CRL Sign' highlighted.

14. Select the 'Netscape' tab.
15. If you clicked 'Apply' to CA template (step 6), you should see 'SSL CA', 's/MIME CA' and 'Object Signing CA' highlighted.

16. Click 'OK' bottom right corner

'MyCA' should now be listed under the main 'Certificates' tab



B. To create the HTTPS Server certificate

1. Select the 'Certificates' tab.
2. Right Click on the 'MyCA' entry -> 'New Certificate'

3. Select the 'Source' tab.
4. Signing -> 'Use this certificate for signing: MyCA'
5. Signature algorithm -> 'SHA 1'
6. Template -> '[default] HTTPS_server'. Click Apply!! Do not forget to apply.

7. Select the 'Subject' tab.
8. At the very least, fill in 'Internal Name', 'Common name', e.g. 'www.mydomain.com' for both. The common name MUST exactly match the full domain name of the webserver to be protected.
9. Private Key -> click 'Generate a new key'

10. Select the 'Extensions' tab
11. Make sure the 'Time range' is appropriate. The default of 365 days may be too short. If changed, be sure to 'Apply'!!

12. Select the 'Key Usage' tab.
13. If you clicked 'Apply' to HTTPS_server template (step 6), you should see 'Digital Signature', 'Non Repudiation' and 'Key Encipherment' highlighted.

14. Select the 'Netscape' tab.
15. If you clicked 'Apply' to HTTPS_server template (step 6), you should see 'SSL Server' highlighted.

16. Click 'OK' bottom right corner,

The new certificate for 'www.mydomain.com' should now be listed below MyCA under 'Certificates' tab ( once Tree View is selected )



C. To create the HTTPS Client certificate

1. Select the 'Certificates' tab.
2. Right Click on the 'MyCA' entry -> 'New Certificate'

3. Select the 'Source' tab.
4. Signing -> 'Use this certificate for signing: MyCA'
5. Signature algorithm -> 'SHA 1'
6. Template -> '[default] HTTPS_client'. Click Apply!! Do not forget to apply.

7. Select the 'Subject' tab.
8. At the very least, fill in 'Internal Name', 'Common name', e.g. 'Tester' for both.
9. Private Key -> click 'Generate a new key'

10. Select the 'Extensions' tab
11. Make sure the 'Time range' is appropriate. The default of 365 days may be too short. If changed, be sure to 'Apply'!!

12. Select the 'Key Usage' tab.
13. If you clicked 'Apply' to HTTPS_client template (step 6), you should see 'Digital Signature', 'Key Encipherment' and 'Data Encipherment' highlighted.

14. Select the 'Netscape' tab.
15. If you clicked 'Apply' to HTTPS_client template (step 6), you should see 'SSL Client' and 'S/MIME' highlighted.

16. Click 'OK' bottom right corner,

The new certificate for 'Tester' should now be listed below MyCA under 'Certificates' tab ( once Tree View is selected )



D. Exporting the server certificate

For apache, I exported as 'PEM Cert + Key' format, giving me the 'www.mydomain.com.pem' file. I also needed to configure the 'MyCA.crt' so that Apache would trust the client certificates signed my 'MyCA'



E. Exporting the client certificates

In order for a client browser to trust the certificate for 'www.mydomain.com', it needs a copy of the Root Certificate, i.e. 'MyCA'

It is possible to include the Root Certificate with the client certificate, by exporting the client certificate ('Tester') as "PKCS #12 with Certificate Chain"

This gives the file 'Tester.p12' that Internet Explorer is happy to import.

BUT, I encountered problems with Firefox (3.5.4). When importing, it still would not trust 'www.mydomain.com'. It turns out that although the import process itself is successful, and the Client and Root certificate are listed under 'Your Certificates' and 'Authorities', Firefox does not seem to find the Root certificate when it makes a https connections to www.mydomain.com.

The solution to this was to first export 'MyCA' in the 'PEM' format as MyCA.crt, and then export the Client Certificate 'Tester' in the 'PKCS #12' format.

Then I imported both separately into Firefox, MyCA.crt as an 'Authority' and Tester.p12 under 'Your Certificates'

And since this method also works for IE, I do this in all cases, so I dont need different certificates for IE and Firefox.



F. One other point...

In the case where client certificates are being used for https access to subversion via TortoiseSVN, it made things easier (although less secure when transferring the .p12 files), to leave the password blank when exporting to the .p12 file format.

Doing this means there is no need to import private keys into TortoiseSVN to be able to open the .p12 file, or being constantly asked for the password for this file whenever using subversion.

Additionally, in order for TortoiseSVN to trust the https server certificate installed on www.mydomain.com, I needed to install my Root Authority cert in TrotiseSVN.

To do this, I need to edit the client's subversion\servers file. In the [globals] section, right at the end of the file, I pointed the 'ssl-authority-files' parameter at a local copy of the 'MyCA.crt' root certificate file.

Tuesday, October 13, 2009

Remote CMD.exe Shell

I've been using SSH on both Windows and Linux for a long time to get remote access to various machines, and to tunnel TCP connections through firewalls.

On windows, this has generally meant installing Cygwin's SSHD server, which gives you the cygwin Bash shell.

While I'm comfortable in a unix environment, when I log into a windows box I generally prefer to see a shell that looks like a standard windows command line, e.g. I generally don't want the slashes going the wrong way, and I don't want the whole windows filesystem visible a few levels too deep (/cygdrive/c/ for example )

I knew about the http://sshwindows.sourceforge.net/ project, but it has not been active for a long time (although It does now look active again). And I dont want to have to install something new, when I already have a working SSHD server on many machines. There's also WinSSHD, but that is not free.

I just discovered, by editing /etc/passwd I can make my existing cygwin SSHD installations give me a CMD.exe prompt instead of a Bash shell.

All I had to do was find the line corresponding to my user, and edit the end of the line, changing '/bin/bash' to '/cygdrive/c/WINDOWS/system32/cmd.exe'

And thats it!

Unfortunately, this stops SCP working. I do know the above OpenSSH for Windows project does not have this problem by using the 'switch.exe' program, but I dont see that included with a standard cygwin installation.

To get around this issue, I just created another user, same as the my first, but with the original '/bin/bash' shell configured instead of cmd.exe. I log in with this user when I need SCP.

Update: It doesn't like tab file completion, Ctrl-C is killing putty instead of the remote application, and I forgot how important 'vim' is in these remote terminals... so I'm switching back to the default bash shell. I can always just start cmd.exe when inside bash...

Tuesday, October 6, 2009

Locking & Lock Free Collections - Multithreaded Performance

Been exploring Lock-free collections lately, for a highly threaded memory based caching project.

Before I really know how well I'm doing, I need to explore the performance of simpler locking collection classes (simple wrappers around Dictionary, using lock {} and ReaderWriterLockSlim) , as well determine the absolute maximum performance, by testing lockless readonly collections (i.e. read-only operations on pre-filled Dictionary)

1.
So, for the baseline absolute maximum performance, I get approx 55M read operation/sec on a simple Dictinary object, with 10K key/value pairs... this throughput varies little for 4 to 64 parallel threads, on a standard quad-core machine.

2.
I then need tested against a wrapper class, that uses an internal Dictinary, but allows parallel reads, and serialised write access using the ReaderWriterLockSlim class.
100% Reads: 2threads: 5.35M reads/sec, 4threads: 5.12M
reads/sec, 16threads: 4.34M reads/sec, 64threads 3.53M reads/sec

Overriding Enum ToString()

Use the [Description] attribute

http://blogs.msdn.com/abhinaba/archive/2005/10/20/483000.aspx

Some other interesting comments in there too...