Quite often I need to create demo environments to demonstrate how to build secure applications using claims based federated security, Active Directory Federation Services (AD FS) and .NET Windows Identity Foundation.

I can always rely on the great source of information available on AD FS 2.0 Content Map wiki site when it comes to AD FS features.

However when it comes to building an environment you always need to create some demo certificates.

Previously I used to rely on this blog post by Zulfiqar from our ADM team at Microsoft to grab the command required to create necessary certificates. Unfortunately since 14th August 2012 Microsoft pushed out security advisory 2551254 that blocks certificates with the key length less than 1024 bits. As the result of the hotfix makecert.exe generated certificates are now blocked. I needed another reliable way to generate certificates.

Adam Conkle from Microsoft support team came to the rescue by providing great PowerShell script that can be used to create certificates in your local machine. I have used it and modified slightly to meet the following requirements:

  • Self-signed certificates in the Local Machine Personal store
  • 2048 length private keys marked exportable
  • Predefined Subject (FQDN of the current machine) with the ability to override
  • Following Enhanced Key Usage (EKU) object identifiers (OIDs) included:
    • Server Authentication
    • Client Authentication
    • Smart Card Authentication
    • Encrypting File System
    • Code Signing
  • Optional installation of the certificate to the Trusted Root Certification Authority to make certificate pass validation check without a configuration override on the local machine.

The script I’ve ended up is below.

 1: #####################################################################
 2: # makecert.ps1
 3: # Version 1.0
 4: #
 5: # Creates self-signed signing certificate and install it to certificate store
 6: #
 7: # Note: Requires at least Windows Vista. Windows XP/Windows Server 2003
 8: # are not supported.
 9: #
 10: # Pavel Khodak, 2012 
 11: # http://blogs.msdn.com/b/pavelkhodak/
 12: # Based on the work of 
 13: # Vadims Podans - http://www.sysadmins.lv/
 14: # Adam Conkle - http://social.technet.microsoft.com/wiki/contents/articles/4714.how-to-generate-a-self-signed-certificate-using-powershell-en-us.aspx
 15: #####################################################################
 16:  
 17: Write-Host "`n WARNING: This script sample is provided AS-IS with no warranties and confers no rights." -ForegroundColor Yellow 
 18: Write-Host "`n This script sample will generate self-signed certificates with private key" 
 19: Write-Host " in the Local Computer Personal certificate store." 
 20:  
 21: $Subject = [string]::Format('{0}.{1}', $env:computername, $env:userdnsdomain)
 22: $CustomSubject = Read-Host "`n Would you like to change subject from $Subject Y/[N]"
 23: if ($CustomSubject -eq "Y") 
 24: {
 25:     $Subject = Read-Host "`n Enter the Subject for certificate"  
 26: }
 27:  
 28: $NotBefore = [DateTime]::UtcNow
 29: # Make certificate valid for 10 years
 30: $NotAfter = $NotBefore.AddDays(365 * 10)
 31:  
 32: $Force = $true
 33: $InstallAsRoot = Read-Host "`n Would you like to install this certificate to Trusted Root Certification Authorities? [Y]/N"
 34: if ($InstallAsRoot -eq "N") 
 35: {
 36:     $Force = $false 
 37: }
 38:  
 39: $OS = (Get-WmiObject Win32_OperatingSystem).Version
 40: if ($OS[0] -lt 6) 
 41: {
 42:     Write-Warning "Windows XP, Windows Server 2003 and Windows Server 2003 R2 are not supported!"
 43: }
 44: else
 45: {
 46:     # while all certificate fields MUST be encoded in ASN.1 DER format
 47:     # we will use CryptoAPI COM interfaces to generate and encode all necessary
 48:     # extensions.
 49:     
 50:     # create Subject field in X.500 format using the following interface:
 51:     # http://msdn.microsoft.com/en-us/library/aa377051(VS.85).aspx
 52:     $SubjectDN = New-Object -ComObject X509Enrollment.CX500DistinguishedName
 53:     $SubjectDN.Encode("CN=$Subject", 0x0)
 54:     
 55:     # Add certificate key usage statements.
 56:     $OIDs = New-Object -ComObject X509Enrollment.CObjectIDs
 57:     
 58:     # define Server authentication enhanced key usage (actual OID = 1.3.6.1.5.5.7.3.1)
 59:     $OID = New-Object -ComObject X509Enrollment.CObjectID
 60:     $OID.InitializeFromValue("1.3.6.1.5.5.7.3.1")
 61:     $OIDs.Add($OID)
 62:  
 63:     # define Client authentication enhanced key usage (actual OID = 1.3.6.1.5.5.7.3.2) 
 64:     $OID = New-Object -ComObject X509Enrollment.CObjectID
 65:     $OID.InitializeFromValue("1.3.6.1.5.5.7.3.2")
 66:     $OIDs.Add($OID)
 67:     
 68:     # define SmartCard authentication enhanced key usage (actual OID = 1.3.6.1.4.1.311.20.2.2) 
 69:     $OID = New-Object -ComObject X509Enrollment.CObjectID
 70:     $OID.InitializeFromValue("1.3.6.1.4.1.311.20.2.2")
 71:     $OIDs.Add($OID)
 72:  
 73:     # define CodeSigning enhanced key usage (actual OID = 1.3.6.1.5.5.7.3.3) from OID
 74:     $OID = New-Object -ComObject X509Enrollment.CObjectID
 75:     $OID.InitializeFromValue("1.3.6.1.5.5.7.3.3")
 76:     $OIDs.Add($OID)
 77:     
 78:     # now we create Enhanced Key Usage extension, add our OIDs and encode extension value
 79:     # http://msdn.microsoft.com/en-us/library/aa378132(VS.85).aspx
 80:     $EKU = New-Object -ComObject X509Enrollment.CX509ExtensionEnhancedKeyUsage
 81:     $EKU.InitializeEncode($OIDs)
 82:     
 83:     # generate Private key as follows:
 84:     # http://msdn.microsoft.com/en-us/library/aa378921(VS.85).aspx
 85:     $PrivateKey = New-Object -ComObject X509Enrollment.CX509PrivateKey
 86:     $PrivateKey.ProviderName = "Microsoft RSA SChannel Cryptographic Provider"
 87:     $PrivateKey.KeySpec = 0x1
 88:     $PrivateKey.Length = 2048
 89:     # set security descriptor
 90:     $PrivateKey.SecurityDescriptor = "D:PAI(A;;0xd01f01ff;;;SY)(A;;0xd01f01ff;;;BA)(A;;0x80120089;;;NS)"
 91:     # key will be stored in local machine certificate store
 92:     $PrivateKey.MachineContext = 0x1
 93:     # export will be allowed
 94:     $PrivateKey.ExportPolicy = 0x1
 95:     $PrivateKey.Create()
 96:     
 97:     # now we need to create certificate request template using the following interface:
 98:     # http://msdn.microsoft.com/en-us/library/aa377124(VS.85).aspx
 99:     $Cert = New-Object -ComObject X509Enrollment.CX509CertificateRequestCertificate
 100:     $Cert.InitializeFromPrivateKey(0x2,$PrivateKey,"")
 101:     $Cert.Subject = $SubjectDN
 102:     $Cert.Issuer = $Cert.Subject
 103:     $Cert.NotBefore = $NotBefore
 104:     $Cert.NotAfter = $NotAfter
 105:     $Cert.X509Extensions.Add($EKU)
 106:     # completing certificate request template building
 107:     $Cert.Encode()
 108:     
 109:     # now we need to process request and build end certificate using the following
 110:     # interface: http://msdn.microsoft.com/en-us/library/aa377809(VS.85).aspx
 111:     
 112:     $Request = New-Object -ComObject X509Enrollment.CX509enrollment
 113:     # process request
 114:     $Request.InitializeFromRequest($Cert)
 115:     # retrievecertificate encoded in Base64.
 116:     $endCert = $Request.CreateRequest(0x1)
 117:     # install certificate to user store
 118:     $Request.InstallResponse(0x2,$endCert,0x1,"")
 119:     
 120:     if ($Force) 
 121:     {
 122:         # convert Bas64 string to a byte array
 123:          [Byte[]]$bytes = [System.Convert]::FromBase64String($endCert)
 124:         foreach ($Container in "Root", "TrustedPublisher") 
 125:         {
 126:             # open Trusted Root CAs and TrustedPublishers containers and add
 127:             # certificate
 128:             $x509store = New-Object Security.Cryptography.X509Certificates.X509Store $Container, "LocalMachine"
 129:             $x509store.Open([Security.Cryptography.X509Certificates.OpenFlags]::ReadWrite)
 130:             $x509store.Add([Security.Cryptography.X509Certificates.X509Certificate2]$bytes)
 131:             # close store when operation is completed
 132:             $x509store.Close()
 133:         }
 134:     }        
 135: }
 136: Write-Host "`n Completed`n" -ForegroundColor Green

You can download this PowerShell script here: http://1drv.ms/1wvPIYZ 

The script will require PowerShell 2.0 and will only run on Windows Vista and above. Windows XP and Server 2003 are not supported.

When you run the script you get a chance to change the default subject name and opt out from certificate installation to the Trusted Root Certification Authority store. If everything was successful you’ll get a picture like this one:

powershell

Now you have certificate installed in your local machine storage and you can start configuring AD FS to use it as signing, encrypting or communication certificates.