__dyld__dyld_start error when launching your iOS app

When starting an app I’m building for iOS I got a runtime error with code __dyld__dyld_start. After some frustration, some googling and some testing I found the solution – setting the -weak-lSystem linker flag in Xcode (Targets -> Your target -> Build Setting tab).

dyld-screenshot

Posted in iOS | Tagged , | Leave a comment

Deleting TFS 2010 work items

This is how to do this:

  • Open a command prompt, change to your Visual Studio 2010 dir (usually “c:\Program Files\Microsoft Visual Studio 10.0\Common 7\IDE”).
  • Execute this command
    witadmin.exe destroywi /id:123 /collection:http://tfs01:8080/tfs/DefaultCollection

    replacing 123 with your work item id and the http://tfs01:8080/tfs/DefaultCollection with your TFS collection url.

Posted in Work | Tagged | Leave a comment

DTS_E_CANNOTACQUIRECONNECTIONFROMCONNECTIONMANAGER when executing a SSIS package

The DTS_E_CANNOTACQUIRECONNECTIONFROMCONNECTIONMANAGER ierror can sometimes be resolved by verifying that the called stored procedure exists and that the executing user account has access to it.

Thank you Microsoft for inventing world’s longest constant name and thus screwing up my WordPress layout!

Posted in Uncategorized, Work | Tagged , | Leave a comment

When IIS 6 doesn’t want to let you in – 401 Access Denied

Had a little fight with my local IIS 6 running on a local user account using integrated authentication. It just wouldn’t let me in, no matter what rights I assigned to the user and to the directory.

Apparently this is a known issue documented here which can be resolved by setting a metabase key with the command below.

cscript adsutil.vbs set w3svc/NTAuthenticationProviders "NTLM"
Posted in Work | Tagged , | Leave a comment

P/Invoke and LoadLibrary / GetProcAddress

A little snippet I wrote while trying to use LoadLibrary/GetProcAddress to call functions and get variable values that are exported by an unmanaged dll with P/Invoke.

extern "C" __declspec(dllexport) const char* _Version = "0.1";

extern "C" __declspec(dllexport) const char* GetMyVersion(void)
{
	return _Version;
}
[TestMethod]
public void TestPinvoke()
{
		IntPtr lib = LoadLibrary(@"C:\Documents and Settings\Administrator\My Documents\Visual Studio 2010\Projects\TestWinDll\Debug\TestWinDll.dll");
		if(lib == IntPtr.Zero)
				throw new Win32Exception(Marshal.GetLastWin32Error());

		IntPtr procAddress = GetProcAddress(lib, "GetMyVersion");
		var gmv = (GetMyVersion)Marshal.GetDelegateForFunctionPointer(procAddress, typeof(GetMyVersion));
		var ver = gmv();

		procAddress = Marshal.ReadIntPtr(GetProcAddress(lib, "_Version"));
		var ver2 = Marshal.PtrToStringAnsi(procAddress);

		if(!FreeLibrary(lib))
				throw new Win32Exception(Marshal.GetLastWin32Error());
}

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate String GetMyVersion();

[DllImport("kernel32", SetLastError = true, CharSet = CharSet.Unicode)]
static extern IntPtr LoadLibrary(string lpFileName);

[DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
static extern IntPtr GetProcAddress(IntPtr hModule, string procName);

[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool FreeLibrary(IntPtr hModule);
Posted in Work | Tagged , , , , | Leave a comment

Real-time CRL validation for X.509 certificates in .NET

This is a continuation of my post on
Avoiding X.509 chain policy caching when using WCF with certificate security.

I wrote the code below to implement certificate validation against a published CRL in real-time. The default mechanism uses a cache / validity period, which might be impractical when you want to deny a revoked certificate at once.

The code looks for a CRL link in the provided certificate and uses it to download the base CRL. It then validates the certificate against the CRL and also retrieves the delta CRL (referenced by the base CRL) and validates against that as well.

I P/Invoked crypto32 API because .NET doesn’t have the necessary classes for handling CRLs.

using System;
using System.ComponentModel;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;

namespace My.IdentityModel
{
    /// <summary>
    /// x509 certificate utilities
    /// Richard Ginzburg - richard@ginzburgconsulting.com
    /// </summary>
    public static class CertUtil
    {
        private const string CERT_CRL_EXTENSION = "2.5.29.31";
        private const string CRL_CRL_EXTENSION = "2.5.29.46";

        public static bool IsCertificateInCrl(X509Certificate2 cert)
        {
            try
            {
                string certCrlUrl = GetBaseCrlUrl(cert);
                return IsCertificateInCrl(cert, certCrlUrl);
            }
            catch
            {
                return false;
            }
        }

        public static bool IsCertificateInCrl(X509Certificate2 cert, string url)
        {
            WebClient wc = new WebClient();
            byte[] rgRawCrl = wc.DownloadData(url);

            IntPtr phCertStore = IntPtr.Zero;
            IntPtr pvContext = IntPtr.Zero;
            GCHandle hCrlData = new GCHandle();
            GCHandle hCryptBlob = new GCHandle();
            try
            {
                hCrlData = GCHandle.Alloc(rgRawCrl, GCHandleType.Pinned);
                WinCrypt32.CRYPTOAPI_BLOB stCryptBlob;
                stCryptBlob.cbData = rgRawCrl.Length;
                stCryptBlob.pbData = hCrlData.AddrOfPinnedObject();
                hCryptBlob = GCHandle.Alloc(stCryptBlob, GCHandleType.Pinned);

                if (!WinCrypt32.CryptQueryObject(
                WinCrypt32.CERT_QUERY_OBJECT_BLOB,
                hCryptBlob.AddrOfPinnedObject(),
                WinCrypt32.CERT_QUERY_CONTENT_FLAG_CRL,
                WinCrypt32.CERT_QUERY_FORMAT_FLAG_BINARY,
                0,
                IntPtr.Zero,
                IntPtr.Zero,
                IntPtr.Zero,
                ref phCertStore,
                IntPtr.Zero,
                ref pvContext
                ))
                {
                    throw new Win32Exception(Marshal.GetLastWin32Error());
                }

                WinCrypt32.CRL_CONTEXT stCrlContext = (WinCrypt32.CRL_CONTEXT)Marshal.PtrToStructure(pvContext, typeof(WinCrypt32.CRL_CONTEXT));
                WinCrypt32.CRL_INFO stCrlInfo = (WinCrypt32.CRL_INFO)Marshal.PtrToStructure(stCrlContext.pCrlInfo, typeof(WinCrypt32.CRL_INFO));

                if (IsCertificateInCrl(cert, stCrlInfo))
                {
                    return true;
                }
                else 
                {
                    url = GetDeltaCrlUrl(stCrlInfo);
                    if (!string.IsNullOrEmpty(url))
                    {
                        return IsCertificateInCrl(cert, url);
                    }
                }
            }
            finally
            {
                if (hCrlData.IsAllocated) hCrlData.Free();
                if (hCryptBlob.IsAllocated) hCryptBlob.Free();
                if (!pvContext.Equals(IntPtr.Zero))
                {
                    WinCrypt32.CertFreeCRLContext(pvContext);
                }
            }

            return false;
        }

        private static bool IsCertificateInCrl(X509Certificate2 cert, WinCrypt32.CRL_INFO stCrlInfo)
        {
            IntPtr rgCrlEntry = stCrlInfo.rgCRLEntry;

            for (int i = 0; i < stCrlInfo.cCRLEntry; i++)
            {
                string serial = string.Empty;
                WinCrypt32.CRL_ENTRY stCrlEntry = (WinCrypt32.CRL_ENTRY)Marshal.PtrToStructure(rgCrlEntry, typeof(WinCrypt32.CRL_ENTRY));

                IntPtr pByte = stCrlEntry.SerialNumber.pbData;
                for (int j = 0; j < stCrlEntry.SerialNumber.cbData; j++)
                {
                    Byte bByte = Marshal.ReadByte(pByte);
                    serial = bByte.ToString("X").PadLeft(2, '0') + serial;
                    pByte = (IntPtr)((Int32)pByte + Marshal.SizeOf(typeof(Byte)));
                }
                if (cert.SerialNumber == serial)
                {
                    return true;
                }
                rgCrlEntry = (IntPtr)((Int32)rgCrlEntry + Marshal.SizeOf(typeof(WinCrypt32.CRL_ENTRY)));
            }
            return false;
        }

        private static string GetBaseCrlUrl(X509Certificate2 cert)
        {
            try
            {
                return (from X509Extension extension in cert.Extensions
                        where extension.Oid.Value.Equals(CERT_CRL_EXTENSION)
                        select GetCrlUrlFromExtension(extension)).Single();
            }
            catch
            {
                return null;
            }
        }

        private static string GetDeltaCrlUrl(WinCrypt32.CRL_INFO stCrlInfo)
        {
            IntPtr rgExtension = stCrlInfo.rgExtension;
            X509Extension deltaCrlExtension = null;

            for (int i = 0; i < stCrlInfo.cExtension; i++)
            {
                WinCrypt32.CERT_EXTENSION stCrlExt = (WinCrypt32.CERT_EXTENSION)Marshal.PtrToStructure(rgExtension, typeof(WinCrypt32.CERT_EXTENSION));

                if (stCrlExt.Value.pbData != IntPtr.Zero && stCrlExt.pszObjId == CRL_CRL_EXTENSION)
                {
                    byte[] rawData = new byte[stCrlExt.Value.cbData];
                    Marshal.Copy(stCrlExt.Value.pbData, rawData, 0, rawData.Length);
                    deltaCrlExtension = new X509Extension(stCrlExt.pszObjId, rawData, stCrlExt.fCritical);
                    break;
                }

                rgExtension = (IntPtr)((Int32)rgExtension + Marshal.SizeOf(typeof(WinCrypt32.CERT_EXTENSION)));
            }
            if (deltaCrlExtension == null)
            {
                return null;
            }
            return GetCrlUrlFromExtension(deltaCrlExtension);
        }

        private static string GetCrlUrlFromExtension(X509Extension extension)
        {
            try
            {
                Regex rx = new Regex("http://.*crl");
                string raw = new AsnEncodedData(extension.Oid, extension.RawData).Format(false);
                return rx.Match(raw).Value;
            }
            catch
            {
                return null;
            }
        }
    }
}

The custom validator is below

using System;
using System.IdentityModel.Selectors;
using System.IdentityModel.Tokens;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;

namespace My.IdentityModel
{
    /// <summary>
    /// Custom x509 certificate validator
    /// Richard Ginzburg - richard@ginzburgconsulting.com
    /// </summary>
    public class MyX509Validator : X509CertificateValidator
    {
        public override void Validate(X509Certificate2 certificate)
        {
            var myChainPolicy = new X509ChainPolicy
                                    {
                                        RevocationMode = X509RevocationMode.Online,
                                        RevocationFlag = X509RevocationFlag.EntireChain,
                                        VerificationFlags = X509VerificationFlags.NoFlag,
                                        UrlRetrievalTimeout = new TimeSpan(0, 0, 10),
                                        VerificationTime = DateTime.Now
                                    };
            var chain = new X509Chain(true) {ChainPolicy = myChainPolicy};

            try
            {
                if (!chain.Build(certificate))
                    throw new SecurityTokenValidationException("Certificate validation failed when building chain");
                if (CertUtil.IsCertificateInCrl(certificate))
                    throw new SecurityTokenValidationException("Certificate is revoked by CRL");
            }
            catch (CryptographicException e)
            {
                throw new SecurityTokenValidationException("Certificate validation failed when building chain, " + e);
            }
        }
    }
}

and finally some crypt32 API

using System;
using System.Runtime.InteropServices;
using System.Text;

namespace My.IdentityModel
{
    public static class WinCrypt32
    {
        #region APIs

        [DllImport("CRYPT32.DLL", EntryPoint = "CryptQueryObject", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern Boolean CryptQueryObject(
            Int32 dwObjectType,
            IntPtr pvObject, 
            Int32 dwExpectedContentTypeFlags,
            Int32 dwExpectedFormatTypeFlags,
            Int32 dwFlags,
            IntPtr pdwMsgAndCertEncodingType,
            IntPtr pdwContentType,
            IntPtr pdwFormatType,
            ref IntPtr phCertStore,
            IntPtr phMsg,
            ref IntPtr ppvContext
            );

        [DllImport("CRYPT32.DLL", EntryPoint = "CertFreeCRLContext", SetLastError = true)]
        public static extern Boolean CertFreeCRLContext(
            IntPtr pCrlContext
        );

        [DllImport("CRYPT32.DLL", EntryPoint = "CertNameToStr", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern Int32 CertNameToStr(
            Int32 dwCertEncodingType,
            ref CRYPTOAPI_BLOB pName,
            Int32 dwStrType,
            StringBuilder psz,
            Int32 csz
        );

        [DllImport("CRYPT32.DLL", EntryPoint = "CertFindExtension", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern IntPtr CertFindExtension(
            [MarshalAs(UnmanagedType.LPStr)]String pszObjId,
            Int32 cExtensions,
            IntPtr rgExtensions
        );

        [DllImport("CRYPT32.DLL", EntryPoint = "CryptFormatObject", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern Boolean CryptFormatObject(
            Int32 dwCertEncodingType,
            Int32 dwFormatType,
            Int32 dwFormatStrType,
            IntPtr pFormatStruct,
            [MarshalAs(UnmanagedType.LPStr)]String lpszStructType,
            IntPtr pbEncoded,
            Int32 cbEncoded,
            StringBuilder pbFormat,
            ref Int32 pcbFormat
        );

        #endregion APIs

        #region Structs
        [StructLayout(LayoutKind.Sequential)]
        public struct CRYPT_OBJID_BLOB
        {
            public uint cbData;
            [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)]
            public byte[] pbData;
        }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
        public struct CERT_PUBLIC_KEY_INFO
        {
            public CRYPT_ALGORITHM_IDENTIFIER Algorithm;
            public CRYPTOAPI_BLOB PublicKey;
        }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        public struct CERT_EXTENSION
        {
            [MarshalAs(UnmanagedType.LPStr)]
            public string pszObjId;
            public bool fCritical;
            public CRYPTOAPI_BLOB Value;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct CERT_CONTEXT
        {
            public uint dwCertEncodingType;
            public IntPtr pbCertEncoded;
            public uint cbCertEncoded;
            public IntPtr pCertInfo;
            public IntPtr hCertStore;
        }

        public struct CERT_INFO
        {
            public int dwVersion;
            public CRYPTOAPI_BLOB SerialNumber;
            public CRYPT_ALGORITHM_IDENTIFIER SignatureAlgorithm;
            public CRYPTOAPI_BLOB Issuer;
            public FILETIME NotBefore;
            public FILETIME NotAfter;
            public CRYPTOAPI_BLOB Subject;
            public CERT_PUBLIC_KEY_INFO SubjectPublicKeyInfo;
            public CRYPTOAPI_BLOB IssuerUniqueId;
            public CRYPTOAPI_BLOB SubjectUniqueId;
            public int cExtension;
            public CERT_EXTENSION rgExtension;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct CRL_CONTEXT
        {
            public Int32 dwCertEncodingType;
            public IntPtr pbCrlEncoded;
            public Int32 cbCrlEncoded;
            public IntPtr pCrlInfo;
            public IntPtr hCertStore;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct CRL_INFO
        {
            public Int32 dwVersion;
            public CRYPT_ALGORITHM_IDENTIFIER SignatureAlgorithm;
            public CRYPTOAPI_BLOB Issuer;
            public FILETIME ThisUpdate;
            public FILETIME NextUpdate;
            public Int32 cCRLEntry;
            public IntPtr rgCRLEntry;
            public Int32 cExtension;
            public IntPtr rgExtension;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct CRYPT_ALGORITHM_IDENTIFIER
        {
            [MarshalAs(UnmanagedType.LPStr)]
            public String pszObjId;
            public CRYPTOAPI_BLOB Parameters;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct CRYPTOAPI_BLOB
        {
            public Int32 cbData;
            public IntPtr pbData;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct FILETIME
        {
            public Int32 dwLowDateTime;
            public Int32 dwHighDateTime;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct CRL_ENTRY
        {
            public CRYPTOAPI_BLOB SerialNumber;
            public FILETIME RevocationDate;
            public Int32 cExtension;
            public IntPtr rgExtension;
        }

        #endregion Structs

        #region Consts

        public const Int32 CERT_QUERY_OBJECT_FILE = 0x00000001;
        public const Int32 CERT_QUERY_OBJECT_BLOB = 0x00000002;
        public const Int32 CERT_QUERY_CONTENT_CRL = 3;
        public const Int32 CERT_QUERY_CONTENT_FLAG_CRL = 1 << CERT_QUERY_CONTENT_CRL;
        public const Int32 CERT_QUERY_FORMAT_BINARY = 1;
        public const Int32 CERT_QUERY_FORMAT_BASE64_ENCODED = 2;
        public const Int32 CERT_QUERY_FORMAT_ASN_ASCII_HEX_ENCODED = 3;
        public const Int32 CERT_QUERY_FORMAT_FLAG_BINARY = 1 << CERT_QUERY_FORMAT_BINARY;
        public const Int32 CERT_QUERY_FORMAT_FLAG_BASE64_ENCODED = 1 << CERT_QUERY_FORMAT_BASE64_ENCODED;
        public const Int32 CERT_QUERY_FORMAT_FLAG_ASN_ASCII_HEX_ENCODED = 1 << CERT_QUERY_FORMAT_ASN_ASCII_HEX_ENCODED;
        public const Int32 CERT_QUERY_FORMAT_FLAG_ALL = CERT_QUERY_FORMAT_FLAG_BINARY | CERT_QUERY_FORMAT_FLAG_BASE64_ENCODED | CERT_QUERY_FORMAT_FLAG_ASN_ASCII_HEX_ENCODED;

        public const Int32 X509_ASN_ENCODING = 0x00000001;
        public const Int32 PKCS_7_ASN_ENCODING = 0x00010000;

        public const Int32 X509_NAME = 7;

        public const Int32 CERT_SIMPLE_NAME_STR = 1;
        public const Int32 CERT_OID_NAME_STR = 2;
        public const Int32 CERT_X500_NAME_STR = 3;

        public const String szOID_CRL_REASON_CODE = "2.5.29.21";

        public enum Disposition : uint
        {
            CERT_STORE_ADD_NEW = 1,
            CERT_STORE_ADD_USE_EXISTING = 2,
            CERT_STORE_ADD_REPLACE_EXISTING = 3,
            CERT_STORE_ADD_ALWAYS = 4,
            CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES = 5,
            CERT_STORE_ADD_NEWER = 6,
            CERT_STORE_ADD_NEWER_INHERIT_PROPERTIES = 7,
        }

        [Flags]
        public enum FindFlags : int
        {
            CRL_FIND_ISSUED_BY_AKI_FLAG = 0x1,
            CRL_FIND_ISSUED_BY_SIGNATURE_FLAG = 0x2,
            CRL_FIND_ISSUED_BY_DELTA_FLAG = 0x4,
            CRL_FIND_ISSUED_BY_BASE_FLAG = 0x8,
        }

        public enum FindType : int
        {
            CRL_FIND_ANY = 0,
            CRL_FIND_ISSUED_BY = 1,
            CRL_FIND_EXISTING = 2,
            CRL_FIND_ISSUED_FOR = 3
        }

        #endregion
    }
}
Posted in Work | Tagged , , , , | Leave a comment

Setting SMSC number on an Android phone

To set the SMS center number on a Samsung Galaxy SII phone do the following:

Open the dialer and enter *#*#4636#*#*. You will be greeted with a nice phone settings menu, one of those settings is named SMSC and is the SMS center number in PDU format. The format is described here along with a nice online converter, but the part we are interested in is the beginning.

For the Swedish provider Telenor the number should be 07916407080007F8 as the phone number to the sms center is +46708000708.

  • the 07 here is the length of information in number of octets.
  • the 91 signifies “international format”, basically a +.
  • The rest is the phone number, in this case 6407080007F8 as the phone number to the sms center is +46708000708, in decimal semi-octets. Because the total number of digits in the phone number is odd an F is added.

I’ve color-coded the number to make it easier to understand the whole decimal semi-octets stuff. If I did help you – leave a comment. 😉

More information on the PDU format is available here.

Posted in Android | Tagged | Leave a comment

Fixing “Value does not fall within the expected range” error in MOSS page settings

I wrote this script to correct the error I got from MOSS when trying to edit page settings. Our site uses an internal url (wwwint.mysite.com) and an external one (www.mysite.com). The page layout seemed to have been reset to use the internal url instead of the external one, which generated the errors.

I first tried to fix the error using the gl-fixpublishingpagespagelayouturl command from Gary Lapointe’s stsadm commands, but that didn’t work, so I wrote my own custom script.

I’m posting the script here as a reference.

[ArgumentException: Value does not fall within the expected range.]
   Microsoft.SharePoint.Library.SPRequestInternalClass.GetFileAndMetaInfo(String bstrUrl, Byte bPageView, Byte bPageMode, Byte bGetBuildDependencySet, String bstrCurrentFolderUrl, Boolean& pbCanCustomizePages, Boolean& pbCanPersonalizeWebParts, Boolean& pbCanAddDeleteWebParts, Boolean& pbGhostedDocument, Boolean& pbDefaultToPersonal, String& pbstrSiteRoot, Guid& pgSiteId, UInt32& pdwVersion, String& pbstrTimeLastModified, String& pbstrContent, Byte& pVerGhostedSetupPath, UInt32& pdwPartCount, Object& pvarMetaData, Object& pvarMultipleMeetingDoclibRootFolders, String& pbstrRedirectUrl, Boolean& pbObjectIsList, Guid& pgListId, UInt32& pdwItemId, Int64& pllListFlags, Boolean& pbAccessDenied, Guid& pgDocId, Byte& piLevel, UInt64& ppermMask, Object& pvarBuildDependencySet, UInt32& pdwNumBuildDependencies, Object& pvarBuildDependencies, String& pbstrFolderUrl, String& pbstrContentTypeOrder) +0
   Microsoft.SharePoint.Library.SPRequest.GetFileAndMetaInfo(String bstrUrl, Byte bPageView, Byte bPageMode, Byte bGetBuildDependencySet, String bstrCurrentFolderUrl, Boolean& pbCanCustomizePages, Boolean& pbCanPersonalizeWebParts, Boolean& pbCanAddDeleteWebParts, Boolean& pbGhostedDocument, Boolean& pbDefaultToPersonal, String& pbstrSiteRoot, Guid& pgSiteId, UInt32& pdwVersion, String& pbstrTimeLastModified, String& pbstrContent, Byte& pVerGhostedSetupPath, UInt32& pdwPartCount, Object& pvarMetaData, Object& pvarMultipleMeetingDoclibRootFolders, String& pbstrRedirectUrl, Boolean& pbObjectIsList, Guid& pgListId, UInt32& pdwItemId, Int64& pllListFlags, Boolean& pbAccessDenied, Guid& pgDocId, Byte& piLevel, UInt64& ppermMask, Object& pvarBuildDependencySet, UInt32& pdwNumBuildDependencies, Object& pvarBuildDependencies, String& pbstrFolderUrl, String& pbstrContentTypeOrder) +215
   Microsoft.SharePoint.SPWeb.GetWebPartPageContent(Uri pageUrl, PageView requestedView, HttpContext context, Boolean forRender, Boolean includeHidden, Boolean mainFileRequest, Boolean fetchDependencyInformation, Boolean& ghostedPage, Byte& verGhostedPage, String& siteRoot, Guid& siteId, Int64& bytes, Guid& docId, UInt32& docVersion, String& timeLastModified, Byte& level, Object& buildDependencySetData, UInt32& dependencyCount, Object& buildDependencies, SPWebPartCollectionInitialState& initialState, Object& oMultipleMeetingDoclibRootFolders, String& redirectUrl, Boolean& ObjectIsList, Guid& listId) +1533
   Microsoft.SharePoint.ApplicationRuntime.SPRequestModuleData.FetchWebPartPageInformationForInit(HttpContext context, SPWeb spweb, Boolean mainFileRequest, String path, Boolean impersonate, Boolean& fGhostedPage, Byte& verGhostedPage, Guid& docId, UInt32& docVersion, String& timeLastModified, SPFileLevel& spLevel, String& masterPageUrl, String& customMasterPageUrl, String& webUrl, String& siteUrl, Guid& siteId, Object& buildDependencySetData, SPWebPartCollectionInitialState& initialState, String& siteRoot, String& redirectUrl, Object& oMultipleMeetingDoclibRootFolders, Boolean& objectIsList, Guid& listId, Int64& bytes) +691
   Microsoft.SharePoint.ApplicationRuntime.SPRequestModuleData.FetchWebPartPageInformation(HttpContext context, String path, Boolean impersonate, Boolean& fGhostedPage, Byte& verGhostedPage, Guid& docId, UInt32& docVersion, String& timeLastModified, SPFileLevel& level, String& masterpageUrl, String& customMasterPageUrl, String& webUrl, String& siteUrl, Guid& siteId, Object& buildDependencySetData) +132
   Microsoft.SharePoint.ApplicationRuntime.SPRequestModuleData.GetWebPartPageData(HttpContext context, String path, Boolean throwIfFileNotFound) +773
   Microsoft.SharePoint.ApplicationRuntime.SPVirtualFile.GetFile(String virtualPath, Boolean fetchContent) +78
   Microsoft.SharePoint.ApplicationRuntime.SPVirtualFile.GetFile(String virtualPath) +30
   Microsoft.SharePoint.ApplicationRuntime.SPVirtualPathProvider.GetFile(String virtualPath) +171
   System.Web.Hosting.VirtualPathProvider.GetFile(String virtualPath) +18
   System.Web.Hosting.VirtualPathProvider.GetFileWithCheck(String virtualPath) +11
   System.Web.FormatterWithFileInfo.GetSourceFileLines(String fileName, Encoding encoding, String sourceCode, Int32 lineNumber) +229
   System.Web.DynamicCompileErrorFormatter.get_MiscSectionContent() +926
   System.Web.ErrorFormatter.GetHtmlErrorMessage(Boolean dontShowSensitiveInfo) +837
   System.Web.HttpResponse.WriteErrorMessage(Exception e, Boolean dontShowSensitiveErrors) +820
   System.Web.HttpResponse.ReportRuntimeError(Exception e, Boolean canThrow, Boolean localExecute) +560
   System.Web.HttpRuntime.FinishRequest(HttpWorkerRequest wr, HttpContext context, Exception e) +333
# Updates page layout (wwwint -> www)

[System.Reflection.Assembly]::LoadWithPartialName(“Microsoft.SharePoint”)
[System.Reflection.Assembly]::LoadWithPartialName(“Microsoft.SharePoint.Publishing”)

$site = new-Object Microsoft.SharePoint.SPSite("http://www.mysite.com/myweb")
$web = $site.OpenWeb("subweb")
$pweb = [Microsoft.SharePoint.Publishing.PublishingWeb]::GetPublishingWeb($web)
$global:page = $pweb.GetPublishingPages()["Pages/mypage.aspx"]
$layout = $global:page.ListItem[[Microsoft.SharePoint.Publishing.FieldId]::PageLayout]
$newlayout = $layout.replace("wwwint", "www")

$global:page.ListItem[[Microsoft.SharePoint.Publishing.FieldId]::PageLayout] = $newlayout
$global:page.ListItem.SystemUpdate()
Posted in Work | Tagged | Leave a comment

Avoiding X.509 chain policy caching when using WCF with certificate security

A while ago my customer came to me with an issue that was a bit tricky to find a solution to.

Their system uses a Windows forms client and a WCF service running on IIS7 on a Windows 2008 R2 server. The users are provided with personal certificates stored on smart cards. Those certificates are then used to authenticate the users with the WCF service using their AD accounts.

The issue my customer was facing was:
1. New employees could not log on to the system until the application pool of the web site running the WCF service was recycled.
2. Employees who got their certificates revokeed COULD log on to the system the application pool of the web site running the WCF service was recycled.

Obviously a (totally unwanted) certificate cache of some sort was causing this behavior, so after digging around a bit I found out that System.IdentityModel was caching the X.509 chain policy in memory.

The relevant web.config settings for the WCF service looked like this:

<clientCertificate>
	<authentication mapClientCertificateToWindowsAccount="true" certificateValidationMode="ChainTrust" revocationMode="Online"/>
</clientCertificate>

To solve this issue I decided to implement a custom X.509 validator that builds a X509Chain manually to prevent the policy from being cached.

I changed the above web.config lines to

<clientCertificate>
	<authentication mapClientCertificateToWindowsAccount="true" certificateValidationMode="Custom" customCertificateValidatorType="My.IdentityModel.MyX509Validator, My.IdentityModel" />
</clientCertificate>

and implemented the custom validator like this:

using System;
using System.IO;
using System.IdentityModel.Selectors;
using System.IdentityModel.Tokens;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;

namespace My.IdentityModel
{
    /// <summary>
    /// Custom x509 certificate validator
    /// Richard Ginzburg - richard@ginzburgconsulting.com
    /// </summary>
    public class MyX509Validator : X509CertificateValidator
    {
        public override void Validate(X509Certificate2 certificate)
        {
            if (certificate == null)
            {
                throw new ArgumentNullException("certificate", "Certificate validation failed, no certificate provided");
            }

            X509ChainPolicy myChainPolicy = new X509ChainPolicy
                                                {
                                                    RevocationMode = X509RevocationMode.Online,
                                                    RevocationFlag = X509RevocationFlag.EntireChain,
                                                    VerificationFlags = X509VerificationFlags.NoFlag,
                                                    UrlRetrievalTimeout = new TimeSpan(0, 0, 10),
                                                    VerificationTime = DateTime.Now
                                                };
            X509Chain chain = new X509Chain(true) {ChainPolicy = myChainPolicy};

            try
            {
                bool ok = chain.Build(certificate);
                if(!ok)
                {
                    foreach (var status in chain.ChainStatus)
                    {
                        Logging.Log("MyX509Validator: Validation failed - " + status.StatusInformation);
                    }
                    throw new SecurityTokenValidationException("Certificate validation failed when building chain");
                }
            }
            catch (CryptographicException e)
            {
                throw new SecurityTokenValidationException("Certificate validation failed when building chain, " + e);
            }
        }
    }
}

This resolved the issue, now the changes in certificate validity take effect immediately.

Some documentation on certificate validity checking can be found here: http://technet.microsoft.com/en-us/library/bb457027.aspx .

Posted in Work | Tagged , , , | 3 Comments

Connecting to Mac OSX Lion with Screen Sharing (VNC)

Today I was having issues with connecting to my Mac running Lion from my Windows 7 laptop. The client let me enter my VNC password and then presented me with the Lion login screen where I couldn’t enter the user password.

After looking around a bit I finally pinpointed the problem to be in the choice of encoding in my UltraVNC client. The setting that finally worked for me is “Tight” but if that doesn’t work for you it might help to just try a couple of different ones!

Posted in Mac | Leave a comment